Mock Verify() Invocation

Mockito : how to verify method was called on an object created within a method?

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.

Mock Verify() Invocation

I'm going to go a step further than Yoshi's comment.

The Performed invocations message tells you the method was called but not with the parameters that you were verifying. My guess based on the messages is that there's something wrong with the first parameter.

You would need to post the test for me to be able to be more specific.

Update (after the Test was added)

Change userMgr.Setup to return your 'user' variable, not a duplicate. Despite what I said earlier, this was the cause of your failure - the code being tested was being given a duplicate, and Moq was correctly saying that your method had not been called with user because it had been called with the duplicate. So changing it to this fixes the problem:

userMgr.Setup(x => x.FindByNameAsync(It.IsAny<string>())).ReturnsAsync(user);

This could be made even stronger if the use of It.IsAny<string>() can be avoided: if the specific string that is expected as a parameter is set up as part of the test setup, then give the value instead.

I suspect both of the "1" strings need to be identical to make this work, so rather than duplicate the string declare a local variable and use that instead of both strings.

I would suggest never using values like 1; prefer to randomly type something, so that it doesn't coincidentally pass. By which I mean, imagine a method which takes two integers as parameters: when calling Setup or Verify for that method, if you use the same value for both those integers, the test could pass even if your code has mistakenly swapped the values over (passing each into the wrong parameter). If you use different values when calling Setup or Verify, then it will only work when the correct value is passed in the correct parameter.

mockRepo.Setup is redundant. Setup allows you to specify how the class behaves but there is nothing else after that on the line, so its redundant and can be removed. Some people use setup along with VerifyAll but you might want to read this discussion about using VerifyAll.

Now change your verify back to using project rather than It.IsAny<Project>(). I would expect it to work.

Update 2

Consider a tiled roof. Each tile is responsible for protecting one small part of the roof, slightly overlapping the ones below it. That tiled roof is like a collection of unit tests when using mocking.

Each 'tile' represents one test fixture, covering one class in the real code. The 'overlapping' represents the interaction between the class and the things it uses, which has to be defined using mocks, which are tested using things like Setup and Verify (in Moq).

If this mocking is done badly, then the gaps between the tiles will be big, and your roof could leak (i.e. your code might not work). Two examples of how mocking can be done badly:

  1. Not checking the parameters which are given to the dependencies, by using It.IsAny when you really don't need to.
  2. Incorrectly defining the behaviour of the mock compared to how the real dependency would behave.

That last one is your biggest risk; but it's no different than the risk of writing bad unit tests (regardless of whether it involves mocking). If I wrote a unit test which exercised the code under test but then failed to make any assertions, or made an assertion about something that doesn't matter, that would be a weak test. Using It.IsAny is like saying "I don't care what this value is", and means you're missing the opportunity to assert what that value should be.

There are times when it's not possible to specify the value, where you have to use It.IsAny, and one other case I'll come back to in a second is also OK. Otherwise, you should always try to specify what the parameters are, either exactly, or at least using It.Is<T>(comparison lambda). The one other time it's ok to use It.IsAny<T>() is when you are verifying that a call has not been made, using Times.Never as a parameter to Verify. In this case, it is usually a good idea to always use it, since it checks the call has not been made with any parameter (avoiding the possibility that you have simply made an error on what parameters are given).

If I wrote some unit tests which gave me 100% code coverage; but didn't test all the possible scenarios, that would be weak unit testing. Do I have any tests to try to find these badly written tests? No, and people who don't use mocking don't have tests like that either.

Going back to the tiled roof analogy... if I didn't have mocking, and had to test each part using the real dependencies here's what my roof would look like. I could have a tile for all of the bits at the bottom edge of the roof. No problem so far. For what would have been the next set of tiles up the roof, for what would have been one tile, I need a triangular tile, covering where that tile would have gone, and covering the tiles below it (even though they are already covered by a tile). Still, not too bad. But 15 tiles further up the roof, this is going to get exhausting.

Bringing that to a real world scenario, imagine I'm testing a client-side piece of code, which uses two WCF services, one of which is a third party that charges per use, one of which is protected by windows authentication, maybe one of those services has complex logic in its business layer before reaching the data layer and interacting with a database, and somewhere in there, I might have some caching. I daresay writing decent tests for this without mocking could be described as overly-convoluted, if it's even possible (in one person's lifetime)...

Unless you use mocking, which allows you to...

  1. Test your code that depends on the third-party code, without making calls into it (acknowledging the risks mentioned earlier about mocking that accurately).
  2. Simulate what would happened if a user with or without the right permissions called the protected WCF service (think about how you would do that from automated tests without mocking)
  3. Test separate parts of code in isolation, which is particularly valuable where complex business logic is involved. This exponentially reduces the number of paths through the code that need to be tested, reducing the cost of writing the tests, and of maintaining them. Imagine the complexity of having to set up the database with all the prerequisites, not just for the data layer tests, but for all of the tests up the call stack. Now what happens when there is a database change?
  4. Test caching by Verifying how many times your mock's method was called.

(For the record, speed of execution of the tests has never played any part in my decision to use mocking.)

Luckily mocking is simple, requiring barely any level of comprehension above what I have spelled out here. As long as you acknowledge that using mocking is a compromise compared to full-on integration testing, it yields the kind of savings in development and maintenance time that any product manager will be grateful for. So try to keep the gaps between your tiles small.

Moq verify method signature sees invocations but doesn't match on them?

THis line will always fail:

_statisticsCollector.Verify(
x => x.Measure(It.IsAny<string>(), It.IsAny<long>(), It.IsAny<IDictionary<string, string>>()), Times.Exactly(5));

This happens because you are saying to the mock that it needs to receive a long in the second argument, BUT the interface says that in the second argument it will receive a decimal:

public interface IStatisticsCollector : IDisposable
{
Task Measure(string metricName, decimal value, IDictionary<string, string> tags = null);
}

Since a decimal can't be a long, your verificatin will always fail.

Mockito verify the last call on a mocked object

Thanks @staszko032, inspired by the ArgumentCaptor, instead of getAllValues and verify the sequence, we can use getValue of captor since captor's getValue always get the last true argument. We can do it like this:

    ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
Mockito.verify(mockedA, Mockito.atLeastOnce()).add(captor.capture());
Assert.assertEquals("2", captor.getValue());

Does when() in Mockito verify invocation with strict parameter?

If you use @RunWith(MockitoJUnitRunner.class) or @ExtendWith(MockitoExtension.class), you will get an UnnecessaryStubbingException after running a test if you provided a mock that is not used.

You can avoid this by setting @MockitoSettings(strictness = Strictness.LENIENT) if you want to.

But even with the UnnecessaryStubbingException, it's still better to do an actual verify inside your test for readability. Your 'verify' can also be stricter than your stub, e.g:

when(mock.method(anyCollection())).thenReturn(...)
...
mock.method(collection);
...
verify(mock).method(argThat(collection -> collection.size()==1));

How to verify a method is called two times with mockito verify()

Using the appropriate VerificationMode:

import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

verify(mockObject, atLeast(2)).someMethod("was called at least twice");
verify(mockObject, times(3)).someMethod("was called exactly three times");

Mockito unable to verify invocation in thread run

You are not actually running your Runnable before the verification step. Rather you are scheduling it to be run at a later time.

Fortunately Mockito provides a way to wait for a response:

scheduler.scheduleAtFixedRate(sampleClass, 0, 1, TimeUnit.SECONDS);
verify(k, timeout(100).atLeastOnce()).put(any(C.class));


Related Topics



Leave a reply



Submit