Search code examples
javaunit-testingjunitconstructorjmockit

How to mock constructor of subclass in Junit?


Classes structures look likes below:

class A {
 protected String a;
 protected String b;

 A(String b1) {
    new A("A111", b1);
 }

 A(String a1, String b1) {
   a = a1;
   b = b1;
 }
}

class B extends A {

  B(String b) {
    super("A", b);
  }
}

I need to write JUnit test case and needs to mock constructor for class A so that whenever object for class B needs to create then mock constructor for class A should get invoke and returns object from mock constructor.

I tried following :

       new MockUp<A>() {

            @Mock
            public void $init(String b1) {
                new A("A11111111", b1);
            }
        };

But object created in mocked constructor hasn't been returned.


Solution

  • Ok, you were on the right path ... it takes a combination of @Mock, MockUp, Invocation and Deencapsulation ... You have to add an Invocation to your $init mock method, and then use Deencapsulation to poke around at A internals. Here's an example. I used your A and B classes, only cleaning them up a little bit and adding getters for ease-of-use. I deliberately did not add setters, so I could show off how to get around a lack of setters.

    package com.example.dcsohl;
    
    import org.junit.Test;
    
    import mockit.Deencapsulation;
    import mockit.Invocation;
    import mockit.Mock;
    import mockit.MockUp;
    
    public class TestTest {
    
        public static class A {
            protected String a;
            protected String b;
    
            public A(String b1) {
                this("A111", b1);
            }
    
            public A(String a1, String b1) {
                a = a1;
                b = b1;
            }
        }
    
        public static class B extends A {
            public B(String b1) {
                super("A", b1);
            }
    
            public String getA() {
                return this.a;
            }
    
            public String getB(){
                return this.b;
            }
        }
    
        @Test
        public void test() {
            new MockUp<A>() {
                @Mock public void $init(Invocation inv, String a1, String b1) {
                    A a = inv.getInvokedInstance();
                    Deencapsulation.setField(a, "b", b1);
                }
            };
    
            B b = new B("foo");
    
            System.out.println(b.getA());
            System.out.println(b.getB());
    
        }
    
    }
    

    You'll note that, at the end, the printouts show that I successfully set the value of b but, having left a alone, it comes out as null.