Search code examples
javaunit-testingmockingjmockit

JMockIt Mock not being applied using Faking : Mocking parents of mocked classes


Ok... I have an answer... see below. Thanks to everyone that helped. I have updated the title as well to better reflect the issues.


UPDATE2: The constructor of the parent class of ClassNotUnderTest (which has parameters) is being called with null parameters, which in turn calls it's parent with the same null parameters, which ends up causing a null exception.

I have tried:

Making mocks of both parents, with only the constructor mocked and used one or both of them when trying out the test. The MockClassNotUnderTest still calls the real constructors.

I tried using the @Mocked annotation in the parameter list for the test method, because I don't really want anything back from those parents... Nope. Causes some other error I don't understand.

I tried putting a super(someParams) call in my $init function, but that won't compile.

HEEEEELLLLLPPPPP!!!!


UPDATE:

Ok, the root of my problem is not the implementation as shown below, but with the mock itself. When the MockClassNotUnderTest makes it's constructor call, it is calling the constructor of the real parent of ClassNotUnderTest. I tried also mocking ParentofClassNotUnderTest, but that just caused NullPointerExceptions... sigh. Still searching, I will post updates as they occur. Any suggestions are welcome.


I am fairly new to JMockIt, but my Java skills are not bad. I am trying to mock a dependency class of the class under test. It appears that the either the real method is being called, or maybe it is the super class (more likely). So any ideas on what I am doing wrong?

Now I know some might comment on how I am setting the error parameter, and how that might be applied etc, and I welcome the comments, but the main problem is that this code is not being mocked properly/at all as far as I can see.

To answer a few questions up front... Yes I searched here, and yes I reviewed the tutorials/documentation at the JMockIt website... had both open as I wrote the code in the first place.

I have several similar situations to resolve, so any help is much appreciated. Thanks in advance.

Something like this:

public ClassUnderTest {

    public someMethodUnderTest (){
        <blah blah setup stuff>
        try{
            somevar = new ClassNotUnderTest(someParamA, someParamB, someParamC);
        } catch(SomeExceptionA sea) {
            System.out.printline("Go boom");
        } <more catches here>
    }
}

My test/mock classes are as follows (JUnit4/JMockIt):

public class TestClassUnderTest{

    ClassUnderTest cut;

    <Before method and constructor with some setup code for cut>

    @Test public void test_someMethodUnderTest(){
        MockClassNotUnderTest notUnderTest = new MockClassNotUnderTest();
        notUnderTest.error = 1;

        try{
            testResults = cut.someMethodUnderTest();
        } catch( SomeExceptionA sea) {
            <test that it went boom>
        }
    }

    public class MockClassNotUnderTest extends MockUp<ClassNotUnderTest> {

        public int error = 4;

        @Mock
        public void $init(someParamA, someParamB, someParamC) throws SomeExceptionA, SomeExceptionB, SomeExceptionC {

            if(error == 0) { thrown new SomeExeptionA(); }
            else if(error == 1) { thrown new SomeExeptionB(); }
            else if(error == 2) { thrown new SomeExeptionC(); }
            else { }
        }
    }
}

Solution

  • My expectation would be that the new MockClassNotUnderTest() you are initializing in the test method does not share state with the new ClassNotUnderTest() that you are initializing in the production code.

    Try making your error a static field, so that it is shared across objects being faked.

    I have written a sample test case showing that your comment below is correct. I cannot replicate your problem unless you post real code... Here is my test:

    public class FakeTest {
    
        public static class Foo {
            public void doSomething() {
                try {
                    Bar b = new Bar(73);
                } catch (Throwable t) {
                    System.out.println("Got a " + t.getClass());
                }
            }
        }
    
        public static class Bar {
            private Integer param;
            public Bar(Integer parameter) {
                System.out.println("Got a real bar with param " + parameter); 
                this.param = parameter;
            }
        }
    
        public static class MockBar extends MockUp<Bar> {
            public int error = 4;
    
            @Mock
            public void $init(Integer parameter) {
                System.out.println("Initing fake with parameter " + parameter);
                if (error==1) {
                    throw new IllegalAccessError();
                }
            }
        }
    
        @Test
        public void fakeTest() throws Exception {
            System.out.println("Testing...");
            MockBar mb = new MockBar();
            mb.error=1;
    
            Foo f = new Foo();
            f.doSomething();
        }
    }
    

    The output, as you would expect, is

    Testing...
    Initing fake with parameter 73
    Got a class java.lang.IllegalAccessError