Simulation of Service using Mockito 2 leads to stubbing error - java

I try to simulate the behaviour of a class, using Mockito.
This worked using Mockito 1.x. Migrating to JUnit 5 and Mockito 2 it seems not to work anymore.
#ExtendWith(MockitoExtension.class)
public class MockitoExample {
static abstract class TestClass {
public abstract int booleanMethod(boolean arg);
}
#Mock
TestClass testClass;
#BeforeEach
public void beforeEach() {
when(testClass.booleanMethod(eq(true))).thenReturn(1);
when(testClass.booleanMethod(eq(false))).thenReturn(2);
}
#Test
public void test() {
assertEquals(1,testClass.booleanMethod(true));
assertEquals(2,testClass.booleanMethod(false));
}
}
The expectation is, that the mocked TestClass shows the behaviour as tested in the test-method.
The error I get is:
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'booleanMethod' method:
testClass.booleanMethod(false);
-> at org.oneandone.ejbcdiunit.mockito_example.MockitoExample.beforeEach(MockitoExample.java:30)
- has following stubbing(s) with different arguments:
1. testClass.booleanMethod(false);
-> at org.oneandone.ejbcdiunit.mockito_example.MockitoExample.beforeEach(MockitoExample.java:29)
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
- stubbing the same method multiple times using 'given().will()' or 'when().then()' API
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
- stubbed method is intentionally invoked with different arguments by code under test
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
For more information see javadoc for PotentialStubbingProblem class.
In both cases, the argument false seems to be matched, though I clearly matched with true.
Is that a bug in Mockito 2.17 or a misunderstanding. How should/can I use Mockito 2.x to simulate calls with different boolean arguments?
The example can also be found on github. But surefire will start the test only using
mvn test -Dtest=MockitoExample
Executing the test using Mockito 2.21 leads to the same results.

Since Mockito 2.20 it is also possible, to add lenient() locally
#ExtendWith(MockitoExtension.class)
public class MockitoExample {
static abstract class TestClass {
public abstract int booleanMethod(boolean arg);
}
#Mock
TestClass testClass;
#BeforeEach
public void beforeEach() {
lenient().when(testClass.booleanMethod(eq(true))).thenReturn(1);
lenient().when(testClass.booleanMethod(eq(false))).thenReturn(2);
}
#Test
public void test() {
assertEquals(1,testClass.booleanMethod(true));
assertEquals(2,testClass.booleanMethod(false));
}
}

With strict stubs (the default behavior of Mockito) calling several whens on the same method will reset that mock. The solution is to call when once and have the logic in an Answer:
#BeforeEach
public void beforeEach() {
when(testClass.booleanMethod(anyBoolean())).thenAnswer(invocationOnMock -> {
if ((boolean) invocationOnMock.getArguments()[0]) {
return 1;
}
return 2;
});
}
Alternatively, you can use lenient mocking, but that's not always a good idea - lenient mocking allows redundant stubbing, and makes it easier for you to make mistakes in your test, which may lead to unnoticed bugs in the "production" code:
#ExtendWith(MockitoExtension.class)
#MockitoSettings(strictness = Strictness.LENIENT)
public class MockitoExample {

Mockito 1 and 2 don't have the same "strictness" level.
Besides by using Mockito 2 with JUnit 4 or 5 the default level will be still different.
To sum up :
3 levels of strictness :
LENIENT : minimum strictness
WARN : extra warnings emitted to the console
STRICT_STUBS : ensures clean tests by throwing exception if potential misuse but may also produce some false positives.
Default effective level according to the APIs used :
Mockito 1 : LENIENT
Mockito 2 with JUnit 4 : WARN
Mockito 2 with JUnit 5 (MockitoExtension.class) : STRICT_STUBS
Mockito 3 : planned to be STRICT_STUBS.
More details
The actual Mockito documentation is very clear about that :
The Strictness javadoc states :
Configures the "strictness" of Mockito during a mocking session.A
session typically maps to a single test method invocation. Strictness
drives cleaner tests and better productivity.The easiest way to
leverage enhanced Strictness is usingMockito's JUnit support
(MockitoRule or MockitoJUnitRunner).If you cannot use JUnit support
MockitoSession is the way to go.
How strictness level influences the behavior of the test (mocking
session)?
1.Strictness.LENIENT - no added behavior.The default of Mockito 1.x.Recommended only if you cannot use STRICT_STUBS nor WARN.
2.Strictness.WARN - helps keeping tests clean and improves debuggability.Reports console warnings about unused stubsand stubbing
argument mismatch (see org.mockito.quality.MockitoHint).The default
behavior of Mockito 2.x when JUnitRule or MockitoJUnitRunner are used.
Recommended if you cannot use STRICT_STUBS.
3.Strictness.STRICT_STUBS - ensures clean tests, reduces test code duplication, improves debuggability.Best combination of flexibility
and productivity. Highly recommended.Planned as default for Mockito
v3.See STRICT_STUBS for the details.
But whatever the thrown exception associated to the message
"has following stubbing(s) with different arguments"
seems to be a excessively strict check.
The exception message proves that in a some way :
However, there are legit scenarios when this exception generates false
negative signal:
...
stubbed method is intentionally invoked with different arguments by code under test
So forbidding it by default seems to be too much.
So if you use JUnit 5, as alternative to STRICT_STUBS you could use WARNING but you generally want to avoid LENIENT that is too quiet.
In addition to MockitoExtension, the mockito-junit-jupiter library provides
#MockitoSettings that may be used at the method level as well as at the class level.
Here is an example :
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
#ExtendWith(MockitoExtension.class)
public class FooTest {
#MockitoSettings(strictness = Strictness.WARN)
#Test
void foo() throws Exception {
List<String> strings = Mockito.mock(List.class);
Mockito.when(strings.add("a"))
.thenReturn(true);
Mockito.when(strings.add("b"))
.thenReturn(false);
}
#Test
void fooKo() throws Exception {
List<String> strings = Mockito.mock(List.class);
Mockito.when(strings.add("a"))
.thenReturn(true);
Mockito.when(strings.add("b"))
.thenReturn(false);
}
}
fooKo() throws the misuse Mockito exception while foo() is successful but provides helpful warnings :
[MockitoHint] FooTest (see javadoc for MockitoHint):
[MockitoHint] 1. Unused -> at FooTest.foo(FooTest.java:19)
[MockitoHint] 2. Unused -> at FooTest.foo(FooTest.java:21)
As other alternative you can also use Mockito.lenient() very well described by
aschoerk to apply the lenient strictness for a specific invocation.
As well as you can set every mock invocations as lenient at the mock instantiation :
#Test
void foo() throws Exception {
List<String> strings = Mockito.mock(List.class, Mockito.withSettings()
.lenient());
....
}

Since the first answer came as a surprise, I checked the following:
interface Poops {
String get(boolean is);
}
#Test
void test1() {
Poops a = mock(Poops.class);
when(a.get(eq(true))).thenReturn("1");
when(a.get(eq(false))).thenReturn("2");
Assertions.assertEquals("1", a.get(true));
Assertions.assertEquals("2", a.get(false));
}
It works with Mockito 2.21.0.
Update:
The problem seems to be the Jupiter Mockito extension which changes the default setting to Strictness.STRICT_STUBS.

Related

Mock inner method which uses local variable as paramenter

I've recently started using Mockito 3 + Junit 5 + Spring 5 and I'm writing some example tests in order to understand how Mockito works. I have a question about inner calls. So, I have a spring component A in which is injected some DAO component someObjectDAO. The A class:
#Component("aClass")
public class A {
#Autowired
private ObjectDAO someObjectDAO;
public Long countRecords() {
ObjectSearchCriteria search = new ObjectSearchCriteria();
return someObjectDAO.count(search);
}
}
I want to test A's countRecords method. I've mocked and injected someObjectDAO like this:
#ExtendWith(MockitoExtension.class)
#ContextConfiguration("contextConfFileSomewhere")
public class ATest {
#Mock
ObjectDAO someObjectDAOMock;
#InjectMocks
A aComponent;
#Test
void testCount() {
ObjectSearchCriteria search = Mockito.mock(ObjectSearchCriteria.class);
Mockito.when(someObjectDAOMock.count(search)).thenReturn(1L);
Assertion.assertEquals(1L, aComponent.countRecords());
}
}
But this way is incorrect, in fact PotentialStubbingProblem is raised.
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'count' method:
someObjectDAO.count(
com.example.java.ObjectSearchCriteria#45cc6b13
);
-> at com.example.java.A.countRecords()
- has following stubbing(s) with different arguments:
1. someObjectDAOMock.count(
Mock for ObjectSearchCriteria, hashCode: 204078646
);
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
- stubbing the same method multiple times using 'given().will()' or 'when().then()' API
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
- stubbed method is intentionally invoked with different arguments by code under test
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
For more information see javadoc for PotentialStubbingProblem class.
If I understand correctly the exception indicates that I'm passing an object different from the actual object used in the code under test, right?
So, how can I mock a inner method which uses a local variable as parameter?
You want to mock the call to ObjectDAO.count which has parameters. Instead of passing an instance of the expected parameter as an argument, you should use an argument matcher:
Mockito.when(someObjectDAOMock.count(Mockito.any(ObjectSearchCriteria.class)))
.thenReturn(1L);
Edit: You should probably never even want to "mock a local variable". Your goal is to test the system under test (countRecords method) without knowing implementation details. All you can do is mock the dependencies.

How to resolve Unneccessary Stubbing exception

My Code is as below,
#RunWith(MockitoJUnitRunner.class)
public class MyClass {
private static final String code ="Test";
#Mock
private MyClassDAO dao;
#InjectMocks
private MyClassService Service = new MyClassServiceImpl();
#Test
public void testDoSearch() throws Exception {
final String METHOD_NAME = logger.getName().concat(".testDoSearchEcRcfInspections()");
CriteriaDTO dto = new CriteriaDTO();
dto.setCode(code);
inspectionService.searchEcRcfInspections(dto);
List<SearchCriteriaDTO> summaryList = new ArrayList<SearchCriteriaDTO>();
inspectionsSummaryList.add(dto);
when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
verify(dao).doSearchInspections(dto);
}
}
I am getting below exception
org.mockito.exceptions.misusing.UnnecessaryStubbingException:
Unnecessary stubbings detected in test class: Test
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at service.Test.testDoSearch(Test.java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.
at org.mockito.internal.exceptions.Reporter.formatUnncessaryStubbingException(Reporter.java:838)
at org.mockito.internal.junit.UnnecessaryStubbingsReporter.validateUnusedStubs(UnnecessaryStubbingsReporter.java:34)
at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:49)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:103)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Please help me how to resolve
At first you should check your test logic. Usually there are 3 cases. First, you are mocking the wrong method (you made a typo or someone changed tested code so that mocked method is no longer used). Second, your test is failing before this method is called. Third, your logic falls in wrong if/switch branch somewhere in the code so that mocked method is not called.
If this is the first case you always want to change the mocked method for the one used in the code. With the second and the third it depends. Usually you should just delete this mock if it has no use. But sometimes there are certain cases in parametrized tests, which should take this different path or fail earlier. Then you can split this test into two or more separate ones but that's not always good looking. 3 test methods with possibly 3 arguments providers can make your test look unreadable. In that case for JUnit 4 you silent this exception with either
#RunWith(MockitoJUnitRunner.Silent.class)
annotation or if you are using rule approach
#Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.LENIENT);
or (the same behaviour)
#Rule
public MockitoRule rule = MockitoJUnit.rule().silent();
For JUnit 5 tests you can silence this exception using this annotation provided in mockito-junit-jupiter package:
#ExtendWith(MockitoExtension.class)
#MockitoSettings(strictness = Strictness.LENIENT)
class JUnit5MockitoTest {
}
Replace #RunWith(MockitoJUnitRunner.class) with #RunWith(MockitoJUnitRunner.Silent.class).
For me neither the #Rule nor the #RunWith(MockitoJUnitRunner.Silent.class) suggestions worked. It was a legacy project where we upgraded to mockito-core 2.23.0.
We could get rid of the UnnecessaryStubbingException by using:
Mockito.lenient().when(mockedService.getUserById(any())).thenReturn(new User());
instead of:
when(mockedService.getUserById(any())).thenReturn(new User());
Needless to say that you should rather look at the test code, but we needed to get the stuff compiled and the tests running first of all ;)
Silent is not a solution. You need fix your mock in your test. See official documentation here.
Unnecessary stubs are stubbed method calls that were never realized during test execution (see also MockitoHint), example:
//code under test:
...
String result = translator.translate("one")
...
//test:
...
when(translator.translate("one")).thenReturn("jeden"); // <- stubbing realized during code execution
when(translator.translate("two")).thenReturn("dwa"); // <- stubbing never realized
...
Notice that one of the stubbed methods were never realized in the code under test, during test execution. The stray stubbing might be an oversight of the developer, the artifact of copy-paste or the effect not understanding the test/code. Either way, the developer ends up with unnecessary test code. In order to keep the codebase clean & maintainable it is necessary to remove unnecessary code. Otherwise tests are harder to read and reason about.
To find out more about detecting unused stubbings see MockitoHint.
when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
verify(dao).doSearchInspections(dto);
The when here configures your mock to do something. However, you donot use this mock in any way anymore after this line (apart from doing a verify). Mockito warns you that the when line therefore is pointless. Perhaps you made a logic error?
Replace
#RunWith(MockitoJUnitRunner.class)
with
#RunWith(MockitoJUnitRunner.Silent.class)
or remove #RunWith(MockitoJUnitRunner.class)
or just comment out the unwanted mocking calls (shown as unauthorised stubbing).
This was already pointed out in this comment, but I think that's too easy to overlook: You may run into an UnnecessaryStubbingException if you simply convert a JUnit 4 test class to a JUnit 5 test class by replacing an existing #Before with #BeforeEach, and if you perform some stubbing in that setup method that is not realized by at least one of the test cases.
This Mockito thread has more information on that, basically there is a subtle difference in the test execution between #Before and #BeforeEach. With #Before, it was sufficient if any test case realized the stubbings, with #BeforeEach, all cases would have to.
If you don't want to break up the setup of #BeforeEach into many small bits (as the comment cited above rightly points out), there's another option still instead of activating the lenient mode for the whole test class: you can merely make those stubbings in the #BeforeEach method lenient individually using lenient().
As others pointed out it is usually the simplest to remove the line that is unnecessarily stubbing a method call.
In my case it was in a #BeforeEach and it was relevant most of the time. In the only test where that method was not used I reset the mock, e.g.:
myMock.reset()
Hope this helps others with the same problem.
(Note that if there are multiple mocked calls on the same mock this could be inconvenient as well since you'll have to mock all the other methods except the one that isn't called.)
Looking at a part of your stack trace it looks like you are stubbing the dao.doSearch() elsewhere. More like repeatedly creating the stubs of the same method.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at service.Test.testDoSearch(Test.java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.
Consider the below Test Class for example:
#RunWith(MockitoJUnitRunner.class)
public class SomeTest {
#Mock
Service1 svc1Mock1;
#Mock
Service2 svc2Mock2;
#InjectMock
TestClass class;
//Assume you have many dependencies and you want to set up all the stubs
//in one place assuming that all your tests need these stubs.
//I know that any initialization code for the test can/should be in a
//#Before method. Lets assume there is another method just to create
//your stubs.
public void setUpRequiredStubs() {
when(svc1Mock1.someMethod(any(), any())).thenReturn(something));
when(svc2Mock2.someOtherMethod(any())).thenReturn(somethingElse);
}
#Test
public void methodUnderTest_StateUnderTest_ExpectedBehavior() {
// You forget that you defined the stub for svcMock1.someMethod or
//thought you could redefine it. Well you cannot. That's going to be
//a problem and would throw your UnnecessaryStubbingException.
when(svc1Mock1.someMethod(any(),any())).thenReturn(anyThing);//ERROR!
setUpRequiredStubs();
}
}
I would rather considering refactoring your tests to stub where necessary.
Well, In my case Mockito error was telling me to call the actual method after the when or whenever stub. Since we were not invoking the conditions that we just mocked, Mockito was reporting that as unnecessary stubs or code.
Here is what it was like when the error was coming :
#Test
fun `should return error when item list is empty for getStockAvailability`() {
doAnswer(
Answer<Void> { invocation ->
val callback =
invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
callback.onApiCallError(stockResultViewStateError)
null
}
).whenever(stockViewModelTest)
.getStockAvailability(listOf(), getStocksApiCallBack)
}
then I just called the actual method mentioned in when statement to mock the method.
changes done is as below
stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)
#Test
fun `should return error when item list is empty for getStockAvailability`() {
doAnswer(
Answer<Void> { invocation ->
val callback =
invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
callback.onApiCallError(stockResultViewStateError)
null
}
).whenever(stockViewModelTest)
.getStockAvailability(listOf(), getStocksApiCallBack)
//called the actual method here
stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)
}
it's working now.
If you're using this style instead:
#Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
replace it with:
#Rule
public MockitoRule rule = MockitoJUnit.rule().silent();
I had UnnecessaryStubbingException when I tried to use the when methods on a Spy object.
Mockito.lenient() silenced the exception but the test results were not correct.
In case of Spy objects, one has to call the methods directly.
#ExtendWith(MockitoExtension.class)
#RunWith(JUnitPlatform.class)
class ArithmTest {
#Spy
private Arithm arithm;
#Test
void testAddition() {
int res = arithm.add(2, 5);
// doReturn(7).when(arithm).add(2, 5);
assertEquals(res, 7);
}
}
In case of a large project, it's difficult to fix each of these exceptions. At the same time, using Silent is not advised. I have written a script to remove all the unnecessary stubbings given a list of them.
https://gist.github.com/cueo/da1ca49e92679ac49f808c7ef594e75b
We just need to copy-paste the mvn output and write the list of these exceptions using regex and let the script take care of the rest.
If you use any() when mocking, you have to relpace #RunWith(MockitoJUnitRunner.class) with
#RunWith(MockitoJUnitRunner.Silent.class).

SonarQube issue "Add at least one assertion to this test case" for unit test with assertions?

I'm having issues with SonarQube raising issues with several of my unit tests, prompting the following issue:
Add at least one assertion to this test case.
Each test case resembles this format (where a number of assertions are delegated to a method with common assertions, to avoid duplication):
#Test
public void companyNameOneTooLong() throws Exception {
AddressFormBean formBean = getValidBean();
formBean.setCompanyNameOne("123456789012345678901234567890123456");
assertViolation(validator.validate(formBean), "companyNameOne", "length must be between 0 and 35");
}
private void assertViolation(Set<ConstraintViolation<AddressFormBean>> violations, String fieldname, String message) {
assertThat(violations, hasSize(1));
assertEquals(fieldname, violations.iterator().next().getPropertyPath().iterator().next().getName());
assertEquals(message, violations.iterator().next().getMessage());
}
Now, obviously I could just pull the three assertions out of the private method and put them in the test method - but I'm performing the same checks (on different fields) multiple times.
So, I thought I'd try to emulate the behaviour of the assertion methods, by (re) throwing an AssertionError:
private void assertViolation(Set<ConstraintViolation<AddressFormBean>> violations, String fieldname, String message) throws AssertionError {
try {
assertThat(violations, hasSize(1));
assertEquals(fieldname, violations.iterator().next().getPropertyPath().iterator().next().getName());
assertEquals(message, violations.iterator().next().getMessage());
} catch (AssertionError e) {
throw e;
}
}
Unfortunately, this approach does not work either.
What's special about the JUnit assert methods / what is SonarQube looking for specifically to check that an assertion has been made for each test?
Alternatively - are there other approaches to achieve the same end result (avoiding duplicating the shared assertion code over and over)?
The rule S2699 (Tests should include assertions) from the SonarQube Java Analyzer does not perform cross-procedural analysis and only explore body of methods being identified as test method (usually annotated with #Test).
Consequently, if the only assertions which will be called when executing the test method are done by a dedicated method (to avoid duplication), then the rule will raise an issue. This is a known limitation of the rule and we will deal with it only when we will be able to efficiently perform cross-procedural analysis.
Regarding the issues raised by SonarQube on such cases, you can safely mark them as Won't Fix.
Regarding the detected assertions, the rule consider as assertions the usual assert/fail/verify/expect methods from the following (unit test) frameworks :
JUnit
Fest (1.x & 2.x)
AssertJ
Hamcrest
Mockito
Spring
EasyMock
If you don't expect any exception to be throw from your test, this can be a workaround:
#Test(expected = Test.None.class /* no exception expected */)
Alternatively, you can suppress the warning for the test method/test class:
#SuppressWarnings("squid:S2699")
One thing I have done in the past is to have the helper method return true, and assert on that:
#Test
public void testSomeThings() {
Thing expected = // . . .
Thing actual = service.methodReturningThing(42);
assertTrue(assertViolation(expected, actual));
}
private boolean assertViolation(Thing expected, Thing actual) {
assertEquals(expected.getName(), actual.getName());
assertEquals(expected.getQuest(), actual.getQuest());
assertEquals(expected.getFavoriteColor(), actual.getFavoriteColor());
return true;
}
I hate this, but I hate duplicated code even more.
The other thing we've done at times, is to simply mark any such objections from SonarQube as Won't Fix, but I hate that, too.
Sometimes you don't need to have any code or assertation, for example, the test of load the context of spring boot successfully. In this case, to prevent Sonar issue when you don't expect any exception to be throw from your test, you can use this part of the code:
#Test
void contextLoads() {
Assertions.assertDoesNotThrow(this::doNotThrowException);
}
private void doNotThrowException(){
//This method will never throw exception
}

Returning String value from the Mockito when()

I am trying to specific String value in mockito using when() method like
#Mock Individual indProvider;
when(indProvider.asProvider().getProviderId()).thenReturn("795316051750");
But I am getting exception
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 recorded.
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
For more info see javadoc for Matchers class.
How can I return specific String in such case?
There's probably somewhere in the code a mockito Matcher used outside of stubbed invocation or verified invocation.
If your code base use JUnit I recommend the use of the mockito runner, it will validate the mockito use for each test method, which means any issue can be pinpointed to the test incorrectly written.
#RunWith(MockitoJUnitRunner.class)
public class TheTest {
#Test public void shoudl_perform_something() { ... }
}
Or with a mockito rule (since 1.10.17)
public class TheTest {
#Rule MockitoRule mockitoRule = MockitoJUnit.rule();
#Test public void should_perform_something() { ... }
}
You don't have to use have #Mocks in your test to benefit from this framework validation.
And anyway both are the preferred ways to instantiate mocks compared to MockitoAnnotations.initMocks(...)
Also which version of mockito are you using ? I believe Mockito has improved some messages with the location of the bad code.
Note that this code cannot work properly, because indProvider.asProvider() is not stubbed so mockito will use the default value which is null. You have to do this either way (deep stubs is here for legacy code, a mock returning a mock is usually considered a code smell and it shows the tested code breaks the Law of Demeter) :
#Mock(answer = RETURNS_DEEP_STUBS) Individual indProvider;
// ...
when(indProvider.asProvider().getProviderId()).thenReturn("795316051750");
or as answered by #przemek, it's more verbose and shows the same weakness in the tested code.
#Mock(answer = RETURNS_DEEP_STUBS) Individual indProvider;
#Mock Provider provider;
// ...
when(indProvider.asProvider()).thenReturn(provider);
when(provider.getProviderId()).thenReturn("795316051750");
I advise you to read this book (Growing Object Oriented Software Guided by Tests), it's one of the very best book you can read about writing softwares guided by tests. I find it even more important than infamous Effective Java book.
You should use multiple when() interceptions:
#Mock Individual indProvider;
#Mock Provider provider;
when(indProvider.asProvider()).thenReturn(provider);
when(provider.getProviderId()).thenReturn("795316051750");
You can solve it like this:
Mockito.when(indProvider.asProvider().getProviderId())
.thenAnswer(t -> "795316051750");

Declaring Jmockit mock parameters on #BeforeMethod of TestNG

I've been testing my code behavior using TestNG and JMockit for a while now and I have had no specific issue with their combination. Today I came across a situation where I needed to mock one of my internal dependencies, in the so called, type wide manner and I did not need to keep that mock around since none of the test cases dealt with it directly while they counted on the mocked version functionality. So, naturally, I put the mocking logic in my #BeforeMethod. Here is a sample:
public class SampleTest
{
#Mocked
#Cascading
private InnerDependency dependency;
#BeforeMethod
public void beforeMethod()
{
new NonStrictExpectations()
{
{
dependency.getOutputStream((String)any);
result = new Delegate<OutputStream>()
{
public OutputStream getOutputStream(String url)
{
return null;
}
};
}
};
}
#Test
public void testNormalOperation()
{
// The test whose desired behavior depends on dependency being mocked out
// ..
}
}
But, since my tests do not care about the mocked dependency explicitly, I'm not willing to declare it as a test class field, unlike what is done above. To my knowledge of JMockit The only options remaining would be:
Declare dependency as a local mock field:
new NonStrictExpectations()
{
#Cascading
private InnerDependency dependency;
{
//...
}
}
Declare dependency as an input argument for beforeMethod(), similar to what is done for normal #Test methods:
#BeforeMethod
public void beforeMethod(#Mocked #Cascading final InnerDependency dependency)
{
// ...
}
I see that JMockit 1.6+ would not like the first option and warns with WARNING: Local mock field "dependency" should be moved to the test class or converted to a parameter of the test method. Hence, to keep everyone happy, I'm ruling this option out.
But for the second option, TestNG (currently 6.8.6) throws exception when running the test saying java.lang.IllegalArgumentException: wrong number of arguments. I don't see this behavior with normal #Test cases passed with #Mocked parameters. Even playing with #Parameter and #Optional will not help (and should not have!).
So, is there any way I could make this work without declaring the unneccessary test class mock field, or am I missing something here?
Thanks
Only test methods (annotated with #Test in JUnit or TestNG) support mock parameters, so the only choice here is to declare a mock field at the test class level.
Even if not used in any test method, I think it's better than having it declared in a setup method (using #Before, #BeforeMethod, etc.). If it were to be possible, the mock would still have to apply to all tests, because of the nature of setup methods; having a mock field of the test class makes it clear what the scope of the mock is.
Dynamic partial mocking is one more technique to specify #Mocked dependencies locally. However, it has it's limitations (see comments below).

Categories