477

I am new to Mockito.

Given the class below, how can I use Mockito to verify that someMethod was invoked exactly once after foo was invoked?

public class Foo
{
    public void foo(){
        Bar bar = new Bar();
        bar.someMethod();
    }
}

I would like to make the following verification call,

verify(bar, times(1)).someMethod();

where bar is a mocked instance of Bar.

mre
  • 43,520
  • 33
  • 120
  • 170
  • 3
    http://stackoverflow.com/questions/6520242/mocking-methods-of-local-scope-objects-with-mockito - But I don't want to use PowerMock. – mre Mar 23 '12 at 16:38
  • Change the API or PowerMock. One of the two. – John B Mar 23 '12 at 16:52
  • How to cover something like this?? public synchronized void start(BundleContext bundleContext) throws Exception { BundleContext bc = bundleContext; logger.info("STARTING HTTP SERVICE BUNDLE"); this.tracker = new ServiceTracker(bc, HttpService.class.getName(), null) { @Override public Object addingService(ServiceReference serviceRef) { httpService = (HttpService) super.addingService(serviceRef); registerServlets(); return httpService; }}} – ShAkKiR Aug 16 '18 at 14:04

8 Answers8

504

Dependency Injection

If you inject the Bar instance, or a factory that is used for creating the Bar instance (or one of the other 483 ways of doing this), you'd have the access necessary to do perform the test.

Factory Example:

Given a Foo class written like this:

public class Foo {
  private BarFactory barFactory;

  public Foo(BarFactory factory) {
    this.barFactory = factory;
  }

  public void foo() {
    Bar bar = this.barFactory.createBar();
    bar.someMethod();
  }
}

in your test method you can inject a BarFactory like this:

@Test
public void testDoFoo() {
  Bar bar = mock(Bar.class);
  BarFactory myFactory = new BarFactory() {
    public Bar createBar() { return bar;}
  };
  
  Foo foo = new Foo(myFactory);
  foo.foo();

  verify(bar, times(1)).someMethod();
}

Bonus: This is an example of how TDD(Test Driven Development) can drive the design of your code.

Riyafa Abdul Hameed
  • 7,417
  • 6
  • 40
  • 55
csturtz
  • 6,380
  • 2
  • 24
  • 34
  • 11
    Is there a way to do this without modifying the class for unit testing? – mre Mar 23 '12 at 16:34
  • 12
    `Bar bar = mock(Bar.class)` instead of `Bar bar = new Bar();` – John B Mar 23 '12 at 16:43
  • 9
    not that I'm aware of. but, I'm not suggesting that you modify the class just for unit testing. This is really a conversation about clean code and the SRP. Or.. is it the responsibility of method foo() in class Foo to construct a Bar object. If the answer is yes, then it's an implementation detail and you shouldn't worry about testing the interaction specifically (refer to @Michael's answer). If the answer is no, then you're modifying the class because your difficulty in testing is a red flag that your design needs a little improvement (hence the bonus I added re how TDD drives design). – csturtz Mar 23 '12 at 16:46
  • @JohnB depends on your approach... I use real objects when possible and only mocks when necessary – csturtz Mar 23 '12 at 16:47
  • 6
    Can you pass a "real" object to Mockito's "verify"? – John B Mar 23 '12 at 16:54
  • 5
    You can also mock the factory: `BarFactory myFactory = mock(BarFactory.class); when(myFactory.createBar()).thenReturn(bar);` – levsa Sep 30 '13 at 09:15
  • I'd love to see other 483 methods. Could you please provide a link @csturtz ? Please! – Roger Alien Nov 18 '17 at 00:06
  • 1
    JohnB - Since this hasn't been answered since 2012: Yes, use @Spy. – Thomas Mar 15 '22 at 10:21
  • is it anno 2023 allready possible somehow to verify methods on objects generated inside the method? Or do you still have to make your code dirty to be able to perform a test? – Yannick Mussche Feb 21 '23 at 14:20
22

The classic response is, "You don't." You test the public API of Foo, not its internals.

Is there any behavior of the Foo object (or, less good, some other object in the environment) that is affected by foo()? If so, test that. And if not, what does the method do?

Michael Brewer-Davis
  • 14,018
  • 5
  • 37
  • 49
  • 5
    So what would you actually test here? The public API of `Foo` is `public void foo()`, where the internals are _only_ bar related. – behelit Feb 17 '16 at 22:23
  • 24
    Testing only the public API is fine, until there are genuine bugs with side-effects that need tests. For example, checking that a private method is closing its HTTP connections properly is overkill until you discover that the private method is *not* closing its connections properly, and is thus causing a massive problem. At that point, Mockito and `verify()` become very helpful indeed, even if you are no longer worshipping at the holy altar of integration testing. – Dawngerpony Jul 18 '16 at 11:16
  • @DuffJ I don't use Java, but that sounds like something that your compiler or code analysis tool should detect. – user247702 Dec 09 '16 at 09:59
  • 3
    I agree with DuffJ, while functional programming is fun, there comes a point where your code interacts with the outside world. Doesn't matter if you call it "internals", "side effects", or "functionality", you definitely want to test that interaction: if it happens, and if it happens the correct number of times and with the correct arguments. @Stijn: it might have been a bad example (but if multiple connections should be opened, and only some of them closed, than it gets interesting). A better example would be to check weather the correct data would have been sent over the connection. – Andras Balázs Lajtha Jul 09 '17 at 07:32
  • 2
    @Dawngerpony private method? These should be avoided. The method that closes the http connection should be public. You would then have a separate unit test for that method which mocks the connection and verifies that 'close' was called on it. Simple. – java-addict301 Feb 16 '21 at 20:23
21

I think Mockito @InjectMocks is the way to go.

Depending on your intention you can use:

  1. Constructor injection
  2. Property setter injection
  3. Field injection

More info in docs

Below is an example with field injection:

Classes:

public class Foo
{
    private Bar bar = new Bar();

    public void foo() 
    {
        bar.someMethod();
    }
}

public class Bar
{
    public void someMethod()
    {
         //something
    }
}

Test:

@RunWith(MockitoJUnitRunner.class)
public class FooTest
{
    @Mock
    Bar bar;

    @InjectMocks
    Foo foo;

    @Test
    public void FooTest()
    {
        doNothing().when( bar ).someMethod();
        foo.foo();
        verify(bar, times(1)).someMethod();
    }
}
siulkilulki
  • 1,054
  • 1
  • 10
  • 18
19

If you don't want to use DI or Factories. You can refactor your class in a little tricky way:

public class Foo {
    private Bar bar;

    public void foo(Bar bar){
        this.bar = (bar != null) ? bar : new Bar();
        bar.someMethod();
        this.bar = null;  // for simulating local scope
    }
}

And your test class:

@RunWith(MockitoJUnitRunner.class)
public class FooTest {
    @Mock Bar barMock;
    Foo foo;

    @Test
    public void testFoo() {
       foo = new Foo();
       foo.foo(barMock);
       verify(barMock, times(1)).someMethod();
    }
}

Then the class that is calling your foo method will do it like this:

public class thirdClass {

   public void someOtherMethod() {
      Foo myFoo = new Foo();
      myFoo.foo(null);
   }
}

As you can see when calling the method this way, you don't need to import the Bar class in any other class that is calling your foo method which is maybe something you want.

Of course the downside is that you are allowing the caller to set the Bar Object.

Hope it helps.

raspacorp
  • 5,037
  • 11
  • 39
  • 51
  • 9
    I think this is an anti-pattern. Dependencies should be injected, period. Allowing an optionally-injected dependency solely for the purpose of testing is intentionally avoiding improving code and is intentionally testing something different than the code that runs in production. Both those are awful, horrible things to do. – ErikE May 01 '18 at 16:38
11

Solution for your example code using PowerMockito.whenNew

  • mockito-all 1.10.8
  • powermock-core 1.6.1
  • powermock-module-junit4 1.6.1
  • powermock-api-mockito 1.6.1
  • junit 4.12

FooTest.java

package foo;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

//Both @PrepareForTest and @RunWith are needed for `whenNew` to work 
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Foo.class })
public class FooTest {

    // Class Under Test
    Foo cut;

    @Mock
    Bar barMock;

    @Before
    public void setUp() throws Exception {
        cut = new Foo();

    }

    @After
    public void tearDown() {
        cut = null;

    }

    @Test
    public void testFoo() throws Exception {

        // Setup
        PowerMockito.whenNew(Bar.class).withNoArguments()
                .thenReturn(this.barMock);

        // Test
        cut.foo();

        // Validations
        Mockito.verify(this.barMock, Mockito.times(1)).someMethod();

    }

}

JUnit Output JUnit Output

javaPlease42
  • 4,699
  • 7
  • 36
  • 65
7

Yes, if you really want / need to do it you can use PowerMock. This should be considered a last resort. With PowerMock you can cause it to return a mock from the call to the constructor. Then do the verify on the mock. That said, csturtz's is the "right" answer.

Here is the link to Mock construction of new objects

John B
  • 32,493
  • 6
  • 77
  • 98
3

I had this very issue today, and I didn't want to use PowerMock or other stuff. I just wanted to make a test that made sure a certain method was called. I found this post and I saw that nobody had mentioned this approach.

One way of achieving this without adding in more dependencies or similar is pretty low tech, but it works:

@Test
public void testSomeMethodIsCalledOnce() throws Exception {
    final AtomicInteger counter = new AtomicInteger(0);
    Mockito.when(someObject.theMethodIWant(anyString()))
        .then((Answer<ReturnValue>) __ -> {
            teller.incrementAndGet();
            return theExpectedAnswer;
        });
    theObjectUnderTest.theMethod(someTestValue);

    assertEquals(1, teller.get());
}

This is pretty simple, and it's easy to see what's going on. When the method I want is called (it's mocked here), do this stuff. Amongst the stuff is a call to incrementAndGet for the AtomicInteger. You could use an int[] here, but that's not as clear in my opinion. We're just using something that's final, which we can increment. That's a limitation of the lambda we're using.

It's a bit crude, but it gets the job done in a simple and straightforward matter. At least if you know your lambdas and Mockito.

Haakon Løtveit
  • 1,009
  • 10
  • 18
1

Another simple way would be add some log statement to the bar.someMethod() and then ascertain you can see the said message when your test executed, see examples here: How to do a JUnit assert on a message in a logger

That is especially handy when your Bar.someMethod() is private.

Nestor Milyaev
  • 5,845
  • 2
  • 35
  • 51