Mockito: how to test that a constructor was called?

31,210

Solution 1

This can't be done with Mockito, since the object being created is not a mocked object. This also means that you won't be able to verify anything on that new object either.

I've worked around this scenario in the past by using a Factory to create the object rather than newing it up. You're then able to mock the Factory to return the object required for your test.

Whether you're happy changing your design to suit your tests is up to you!

Solution 2

You can do it with Mockito and PowerMockito.

Say you have ClassUnderTest with a constructor

public class ClassUnderTest {
    String name;
    boolean condition;

    public ClassUnderTest(String name, boolean condition) {
       this.name = name;
       this.condition = condition;
       init();
    }

    ...
}

And another class that calls that constructor

public class MyClass {

    public MyClass() { } 

    public void createCUTInstance() {
       // ...
       ClassUnderTest cut = new ClassUnderTest("abc", true);
       // ...
    }

    ...
}

At the Test class we could...

(1) use PowerMockRunner and cite both target classes above in the PrepareForTest annotation:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ ClassUnderTest.class, MyClass.class })
public class TestClass {

(2) intercept the constructor to return a mock object:

@Before
public void setup() {
    ClassUnderTest cutMock = Mockito.mock(ClassUnderTest.class);
    PowerMockito.whenNew(ClassUnderTest.class)
                .withArguments(Matchers.anyString(), Matchers.anyBoolean())
                .thenReturn(cutMock);
}

(3) validate the constructor call:

@Test
public void testMethod() {
    // prepare
    MyClasss myClass = new MyClass();

    // execute
    myClass.createCUTInstance();

    // checks if the constructor has been called once and with the expected argument values:
    String name = "abc";
    String condition = true;
    PowerMockito.verifyNew(ClassUnderTest.class).withArguments(name, condition);
}

Solution 3

With Mockito can do something

try (MockedConstruction<MyClass> myclass = Mockito.mockConstruction(
        MyClass.class)) {
    ........
    Assert.assertEquals(1, myClass.constructed().size());
}

Solution 4

verify() method waits for mocked object(already created object). And constructor can not be called on created object.

Solution 5

This is not possible with Mockito and sounds like a bad design.

You can use a factory and pass it to the object under test. After that you can easily mock the factory and verify that its create method was called.

By directly creating objects in your code you are making a hard dependency to concrete implementations, which makes the code harder and sometimes impossible to unit test. This is addressed with Dependency Injection (DI) and Inversion of Control (IoC).

Share:
31,210

Related videos on Youtube

java123999
Author by

java123999

Updated on February 16, 2022

Comments

  • java123999
    java123999 over 2 years

    I am using Mockito to test methods within my Java application.

    How can I test that a constructor was called once?

    I am trying to do a verification similar to this:

    verify(myClass, times(1)).doSomething(anotherObject);
    

    But I can't verify that the constructor was called as it doesn't have a method similar to e.g. doSomething().

    • Marcus Müller
      Marcus Müller almost 8 years
      Um, you can't get an Object if you don't call it's constructor; that's a language feature.
    • java123999
      java123999 almost 8 years
      please explain what you mean
    • Rogério
      Rogério almost 8 years
      You should describe what it is that you're actually trying to test, that made you think you needed to mock a constructor. I wouldn't be surprised if there is no real need for it.
  • Wim Coenen
    Wim Coenen almost 8 years
    OP isn't asking how to verify that the constructor works, but how to verify that some other code indeed calls the constructor.
  • java123999
    java123999 almost 8 years
    This seems the best fix. Ill look into using a Factory class in future to solve this
  • Rogério
    Rogério almost 8 years
    Introducing a factory to work around a limitation in the mocking library... that's obviously not a good solution. Instead, I would suggest to avoid the supposed need to mock the class being instantiated from the SUT. Usually, a better test with no mocking is possible.
  • Willie Z
    Willie Z over 6 years
    I think the sequence of the last two lines in your testMethod() should swap. like this: new ClassUnderTest(name, condition); PowerMockito.verifyNew(ClassUnderTest.class);
  • Jose Tepedino
    Jose Tepedino over 6 years
    @WillieZ, thank you so much for calling my attention about this test method! In truth, that previous last command was not really needed. The original idea was to test the constructor call with certain specific argument values, in a method under test called in the execute phase. I've just rewritten the code to express my original intention. I hope it is clearer now.
  • Riding Cave
    Riding Cave over 3 years
    verify(MyClass.class,times(1)).newInstance();
  • Dustin
    Dustin over 2 years
    This does not work. The first argument passed to verify() must be a mock.