Mockito Invalid use of matchers Mock(Object.class) & anyString() - java

Ola,
I'm busy writing a unit test like
monitor.severe(mock(MonitorEventType.class), anyString());
When I execute this I get:
Invalid use of argument matchers.
0 matchers expected, 1 recorded.
So I tried:
monitor.severe(mock(MonitorEventType.class), eq(anyString()));
But this gave
Invalid use of argument matchers.
0 matchers expected, 2 recorded.
I also tried to use
monitor.severe(any(MonitorEventType.class), anyString());
but this gives a null pointer.
What works is
monitor.severe(mock(MonitorEventType.class), "");
But thats not what I want.
My testMethod is :
#Test
public void testSevere() {
monitor.severe(mock(MonitorEventType.class), eq(anyString()));
ArgumentCaptor<DefaultMonitoringEventImpl> captor = ArgumentCaptor.forClass(DefaultMonitoringEventImpl.class);
verify(event).fire(captor.capture());
DefaultMonitoringEventImpl input = captor.getValue();
assertThat(fetchMonitorLevel(input), equalTo(MonitorEventLevel.SEVERE.getDescription()));
}
private String fetchMonitorLevel(DefaultMonitoringEventImpl input) {
Map<String, String> map = input.getMonitorEventWaardes().getWaardenLijst();
return map.get(MonitorEvent.MONITOR_EVENT_LEVEL_KEY);
}
And the method under test is:
public void severe(MonitorEventType type, String message) {
write(type, MonitorEventLevel.SEVERE, message, null);
}
#Asynchronous
public void write(MonitorEventType type, MonitorEventLevel level, String message, MonitorEventWaardes pEventWaardes) {
event.fire(new DefaultMonitoringEventImpl(type, level, message, pEventWaardes));
}
What I want is that When I call monitor.severe with a random MonitorEventType and a random String that the "level" parameter in teh event.fire call is filled with the right value.

First, some basics:
A mock is a replacement for a real object, that you can create using a mock framework. It records its interactions and verifies them for later.
A matcher like any, anyString, or eq tells your mock framework (not your test framework or your system under test) what kind of calls are relevant for stubbing (telling your mock how to behave when its method is called) or verifying (asking your mock framework whether or not a certain method was called).
Most importantly, JUnit and Mockito do not allow for statements like "test this for any input": Statements like any only exist so you can say "when I receive any parameter, take this action" or "check that a method was called with any parameter".
So now your examples:
/* BAD */ monitor.severe(mock(MonitorEventType.class), anyString());
This doesn't work because monitor is real, so anyString is out of place. Your mock is fine there, though, because you're supplying a mock implementation to test a real implementation.
/* BAD */ monitor.severe(mock(MonitorEventType.class), eq(anyString()));
This is the same problem as above, but doubly so: eq should take a real value, never a matcher like anyString.
/* BAD */ monitor.severe(any(MonitorEventType.class), anyString());
Here you've supplied two matchers into a real method call. The matchers are just a signal to Mockito, and a real implementation is processing this, not Mockito.
/* OK */ monitor.severe(mock(MonitorEventType.class), "");
You're supplying a mocked implementation and a real string to your real system-under-test, so this is a proper use of Mockito, even if it doesn't express what you want to test.
Besides the use of Mockito, the real issue here is that you want to introduce randomness into your test. Even if Mockito were the right tool for the job—it definitely isn't—then your test might pass 90% of the time and fail 10% of the time depending on which input is picked. This will make your tests noisy/flaky at best, and may even lead your team to dismiss the value of testing in general.
Instead, pick representative use cases or edge cases; if you have an enum-type parameter, you can also iterate across all values and run the test once per value. You probably don't need Mockito for this, unless you can't easily create a MonitorEventType instance for some reason; then you might use Mockito to create a fake MonitorEventType for interacting with your real Monitor under test.

Related

Is it recommended to use any() or a specific value for unit tests

I am curious about the best / recommended approach to follow when writing a unit test.
If I can easily create the specific values that would get passed for a function, should I create those in my unit tests and use them? Or can I use any() to mock for all values?
class Foo {
bool func1(String abc, int xyz, Bar bar) {
// ...
}
}
If I have a class like this that I want to mock for a specific behavior, which is a better approach?
#Mock
Foo mockFoo;
Bar dummyBar = getTestBar();
when(mockFoo.func1("value1", 1, dummyBar)).thenReturn(true);
when(mockFoo.func1(anyString(), anyInt(), any())).thenReturn(true);
I am trying to identify when to use each. I feel using specific values will be better whenever possible and if it is simple to create those values. Use any() only when it is not easy to create such objects. i.e. Say I am refactoring a codebase and I see almost all unit tests are using any() even if I could use specific values. Will it be worth doing some cleanup on the code and make the unit tests use specific values?
For a function install(String id), any of the following are possible:
id will be a random and unpredictable set of characters such that anyString() is the best you can do. If you were to pick a value, it risks the test failing at random, making the code brittle or flaky.
id should be "yourProgramName" specifically, and any deviation should fail the test. This is where eq and raw values would be appropriate.
id should be "yourProgramName", but that's important to some test other than the one you're writing right now, so it should be eq in the id-validating test and anyString here.
It is entirely up to you: You'll need to pick which parameters matter to your test, and whether your test errs on the side of brittle (failing when it should pass) or permissive (passing when it should fail).
As a side note, you can mix any combination of specific matchers like eq and general matchers like anyString, or you can use all real values that test equals just like eq; you just can't mix both styles in the same call.
/* Any mix of matchers is OK, but you can't mix unwrapped values. Use eq() instead. */
/* bad: */ when(mockFoo.func1( "example" , anyInt(), any())).thenReturn(true);
/* good: */ when(mockFoo.func1(eq("example"), anyInt(), any())).thenReturn(true);
/* Unwrapped values are OK as long as you use them for every parameter you pass. */
/* good: */ when(mockFoo.func1( "example" , 0 , bar1 )).thenReturn(true);
/* same: */ when(mockFoo.func1(eq("example"), eq(0), eq(bar1))).thenReturn(true);

good practice for testing mocked object

It is good practise to match mock objects widely but verify them precisely.
for example:
Using this:
when(myMock.has(any())).thenReturn(myValue);
Rather than:
when(myMock.has(eq("blah")).thenReturn(myValue);
Along with:
var result = myMethod();
assertThat(result, is(myValue));
Because it is making sure that it is always returned myValue regardless of the has method input.
There was a good explanation for this rule but I can not find it.
something along the lines: match widely and verify precisely.
It would be great if you can advise me about the name of the rule or some reference to it?
The explanation is quite simple: It will make your live easier.
Imagine the case that a caller will not call your method with "blah". In this case you rely on the mocking framework what will be returned, most likely null, zero or false. Your test will then run into a different direction or even fail with a NullpointerException. For other developers it will be hard to understand what went wrong here.
If you match widely, your test will continue as expected, but you should place a verification afterwards that makes the test fail with a clean reason. Developers tend to omit the verification step, wich renders the test useless quite often.
Usually there is no reason to match on a precise parameter value, except for the case when you want your mock to act differently on two values.
Most frameworks provide methods for the method call verification, e.g. Mockito:
#Mock
private Repository repository;
#Test
private void testReadData() {
Mockito.when(repository.findById(any())).thenReturn(yourEntity);
// run your test
Mockito.verify(repository).findById("foo");
}

Mockito keeps returning Empty List

I'm working on unit testing a method in Mockito and mockito keeps sending an empty zero size list even when I have initialized the list that is to be returned.
This is the code to be tested. Note that nonCashIncludedPaymentPlanActive is always true ( Mocked ).
List<DebtAccountTransaction> debtAccountTransactionList = null;
boolean nonCashIncludedPaymentPlanActive = balancingPlanService.checkNonCashIncludedPaymentPlanParameter(debtAccountId);
if (nonCashIncludedPaymentPlanActive) {
debtAccountTransactionList = debtAccountTransactionDao
.getDebtAccountTransactionListByDebtAccountIdListWithCN(baseDebtIdAccountList, null);
}
if (debtAccountTransactionList.isEmpty()) {
throw new SfcException("DISPLAY.PAYMENT_PLAN_WITH_NO_BALANCE_SERVICE_FILE_CLOSED");
}
This the statement that keeps returning a List that I have mocked in mockito and added an item to it and here it returns an emptylist.
debtAccountTransactionList = debtAccountTransactionDao
.getDebtAccountTransactionListByDebtAccountIdListWithCN(baseDebtIdAccountList, null);
which then ofcourse gets caught by this line
if (debtAccountTransactionList.isEmpty()) {
throw new SfcException("DISPLAY.PAYMENT_PLAN_WITH_NO_BALANCE_SERVICE_FILE_CLOSED");
}
Thus inorder to avoid this path of execution I have done the following in Mockito:
when(debtAccountTransactionDao.getDebtAccountTransactionListByDebtAccountIdListWithCN(baseDebtIdAccountList, null)).thenReturn(
debtAccountTransactionList);
and declaration of debtAccountTransactionList is :
DebtAccountTransaction debtAccountTransaction = spy(DebtAccountTransaction.class);
debtAccountTransaction.setId(2L);
List<DebtAccountTransaction> debtAccountTransactionList = new ArrayList<DebtAccountTransaction>();
debtAccountTransactionList.add(debtAccountTransaction);
I tried mocking a List, tried different argument captors but nothing seems to work. When I debug it, Mockito does fill up the debtAccountTransactionList but with an empty List, thus it fails.
Any help with how I can make sure that Mockito sends a Non-Empty Non-Zero List so that it can bypass the isEmpty() check.
A good rule of thumb in writing tests, especially with a mocking library like Mockito: Don't confuse stubbing with verification. Stubbing (when) is about getting your system under test (SUT) into the desired state, not about asserting anything about how the SUT behaves.
In Mockito, the way to make assertions about how the SUT behaves is after the SUT runs, using verify calls. If you don't have any verify calls, you're not actually asserting anything, and your SUT can misbehave without your test catching it, which is obviously a bad thing.
As a result, it's usually best to make your matchers for stubbing (when) as broad as possible, since the goal of stubbing is just to make sure you fall into the right test case. For example, you can and often should use matchers like any() in your when() call. If you did that, you would sidestep the issue you're having here.
If you want to make assertions about the values that the SUT actually used as arguments, do that with verify, or possibly by capturing the value and making additional assertions about it directly.
The problem is the mock creation/behavior registration. This doesn't match what you put into the method and hence returns to the default behavior of returning an empty list.
as pointed out by M. Deinum
Thus there was a problem in acceptance of the argument by Mockito and it would ignore my stubbing and then return an empty list by default.
I fixed it by making sure the object that is baseDebtIdAccountList passed to the function when(debtAccountTransactionDao.getDebtAccountTransactionListByDebtAccountIdListWithCN(baseDebtIdAccountList, null)).thenReturn(
debtAccountTransactionList) is exactly the same in the rest of the code. Thus there was a mismatch in the arguments and Mockito used the default way of using an empty list.
Did you put in any place of the code something like:
debtAccountTransactionDao = Mockito.mock(NameOfTheClassOfThisDebtAccountObject.class);
?
You should put something like this before calling the method getDebtAccountTransactionListByDebtAccountIdListWithCN, so it knows it should use the mocked behavior, not the normal behavior of the method (that could be return an empty list).

AnyString() as parameter for unit test

I have to deal with a legacy application that has no tests. So before I begin refactoring I want to make sure everything works as it is.
Now imagine the following situation:
public SomeObject doSomething(final OtherObject x, final String something) {
if(x == null) throw new RuntimeException("x may not be null!");
...
}
Now I want to test that null check, so to be sure it works and I don't lose it once I refactor.
So I did this
#Test(expected = RuntimeException.class)
public void ifOtherObjectIsNullExpectRuntimeException() {
myTestObject.doSomething(null, "testString");
}
Now, this works of course.
But instead of "testString" I'd like to pass in a random String.
So I tried with:
#Test(expected = RuntimeException.class)
public void ifOtherObjectIsNullExpectRuntimeException() {
myTestObject.doSomething(null, Mockito.anyString());
}
But this is not allowed., as I get org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
... You cannot use argument matchers outside of verifications or stubbing
I do understand the meaning of this, but I wonder whether I can still manage to do what I want without parameterizing my test or the like.
The only libraries I may use are Junit, AssertJ, Mockito and Powermock.
Any ideas?
Tests should be deterministic. Using random values in a test makes it difficult to reproduce behavior when debuging a failed test. I suggest that you just create a String constant for the test such as "abcdefg".
Well, like Mockito is trying to tell you via that exception, that's not really how you'd use anyString. Such methods are only to be used by mocks.
So, why not try testing with an actual random string? My personal favorite in such a scenario: java.util.UUID.randomUUID().toString(). This will virtually always generate a brand new string that has never been used for your test before.
I'd also like to add that if you are writing tests for your SomeObject class that you should avoid mocking SomeObject's behavior. From your example, you weren't exactly doing that, but it looked like you might be going down that route. Mock the dependencies of the implementation you're trying to test, not the implementation itself! This is very important; otherwise you aren't actually testing anything.
You are mixing up concepts here.
All those "mocking" helpers like anyString() are meant to be used when configuring a mock object.
But when you check your testing code:
#Test(expected = RuntimeException.class)
public void ifOtherObjectIsNullExpectRuntimeException() {
myTestObject.doSomething(null, "testString");
}
you will find: there is absolutely no mocking involved for this test. You simply can't use those Mockito calls in that place; because "there is no Mockito" in that place.
And just for the record - no need to go overboard here anyway. Your logic is very clear here: when the first argument is null, then you throw that exception. Thus it really doesn't matter at all what comes in as second argument. So thinking for an hour how to test null with any second argument is, well, in my eyes: waste of your time.
Final hint: there is java.lang.Objects
And that class has a nice check for null, so my production code only looks like
public SomeObject doSomething(final OtherObject x, final String something) {
Objects.requireNonNull(otherObject, "otherObject must not be null");
Objects.requireNonNull(something, "something must not be null");
Only difference there: requires... throws NullPointerExceptions
Final finally: some people suggest to put final on every parameter; but I wouldn't do that. It adds no value in 99% of all cases. It just means that you have more code to read; for no good reasons. But that is a question of style.
EDIT on the comment about having a test to check for potential future changes: you shouldn't do that:
To a certain degree, how your input is verified is an implementation detail. You don't test for implementation details. In other words:
Your method has a certain contract (that you, for example specify informally by writing a javadoc that says "throws NPE on null input"). Your tests should verify exactly that current contract. And the contract is: throws if first argument is null.
And maybe another point of view; as I still think you are wasting your time here! You should make sure that all your interfaces are clear, easy to understand, and easy to use. That they allow users of your code to do the right thing easily; and prevent him from doing wrong things. That is what you should focus on - the quality of your interfaces as a whole!
So instead of worrying how you could write a test for potential future changes; just make sure that your code base is overall consistent.
Well i do not have much knowledge of mockito but you can always create your own random string generator. maybe that can work and u can modify more types of inputs in it

Verify with mocks an error message where result can change based on id

So I've got some unit tests where I'm mocking a number of objects, and using those to write tests.
I'm setting the mock objects using anyInt() argument matcher. I want to verify a method called displayErrorMessage(String errorMsg). This method accepts a string, and outputs it into the GUI. The String it accepts is formatted before being sent to the display method with the relevant member Id.
I want to use the argument matcher again in a String format to pass the correct error message to the verify statement.
String.format("Member %d cannot borrow at this time.", anyInt());
I know anyInt() returns zero. I can just manually verify the displayErrorMessage() assuming this, but that seems incorrect.
Current test code:
#Test
public void borrowingRestrictedWhenCardSwipedHasExceededFineLimit() throws Exception {
when(memberDAO.getMemberByID(anyInt())).thenReturn(member);
when(member.hasReachedFineLimit()).thenReturn(true);
ctl.initialise();
ctl.cardSwiped(anyInt());
String errorMessage = "Member %d cannot borrow at this time.";
errorMessage = String.format(errorMessage, anyInt());
verify(ui).displayErrorMessage(errorMessage);
}
This verify would work in this situation:
verify(ui).displayErrorMessage("Member 0 cannot borrow at this time.");
If I'm approaching this incorrectly, whats a better way to do this?
Since this explanation is a little bit longer, here an answer...
anyInt() is used as an argument when a matching is wanted. There are two main cases for that:
when( myMock.someMethod( anyInt() ).thenReturn( x );
This makes myMock return "x" whenever someMethod is called - regardless what the actual int in question was. So...
myMock.someMethod( 12 ) // will return x
myMock.someMethod( -180 ) // will return x
myMock.someMethod( 42 ) // will return x
// etc. ANY int parameter you give, will lead to x, since you told Mockito so in the when statement.
The other way to use it, is to verify:
verify(myMock, times(1)).someMethod( anyInt() );
This will only throw an error if someMethod was NEVER called with any int. If it was called with 12 or -180 or 42 or 1 or 2 or 3, etc. this will be fine (as long as it was called exactly once - not once per int, but once total).
Of course anyInt() has an int value, since it must be put into an int's place, but I would totally ignore that value and never rely on it.
When calling the real method in the end, you should NOT use anyInt() but a real value, since this will give you more control. In your case, I would NOT use anyInt() at all, to be honest:
#Test
public void borrowingRestrictedWhenCardSwipedHasExceededFineLimit() throws Exception {
when(memberDAO.getMemberByID(42)).thenReturn(member);
when(member.hasReachedFineLimit()).thenReturn(true);
ctl.initialise();
ctl.cardSwiped(42);
String errorMessage = "Member %d cannot borrow at this time.";
errorMessage = String.format(errorMessage, 42);
verify(ui).displayErrorMessage(errorMessage);
}
Why? Because this way you can be sure, that when ctl.cardSwiped is called, it will actually use the parameter for the memberDAO.getMemberByID call. With anyInt() you cannot. For example, there could be an error in ctl.cardSwiped:
memberDao.getMemberById( parameter - 1);
With anyInt() in your when, your result would still be the member.
You know that your test case will give 42 as a parameter and ONLY when 42 is given, you want to return the member. So you test that the parameter given is actually used for the call of the internal (memberDao) object.
So, at least call the ctl. with a real number instead of anyInt, preferably even replace all the anyInt() calls, since they don't actually improve your test case here, but actually reduce the quality of the test.
Using anyInt does not mean that the test proves that any int will work. WHAT ints to use is your job to know. For example, are negative ints allowed? Zero? etc.
Edit: Since it has been brought up in another answer... Yes, of course another possibility would be to "dumb down" the error message that it doesn't need the actual id. The question is: Is the error message important? Is the id there important? I would guess yes, but the it depends on the use case. So, IF the exact error message is important, you will have to verify the exact error message - and adjust your test if the error message gets changed. But that's totally ok, the tests are there to ensure a specific behaviour - if the exact error message is important, is it part of that specific behaviour and must be tested. And if this behaviour then changes, the job of the unit tests is to cry "Boo-Hoo, that method doesn't do what it's supposed to do anymore.". That's what unit tests are for.
If the specific error mesage is not important but it is important that it contains the id, then you could verify against that (using contains or an ArgumentCaptor).
If it's only important THAT an the error method is called, regardless of the actual message, then verify against anyString() and be done with it.
Answer interface can be used to interact with the mock and the parameters with which its methods are invoked.
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) throws Throwable {
String msg = (String) args[0];
//Asserting the arguments with which mock method was invoked
Assert.assertEquals("expected", msg);
return null;
}
}).when(ui).displayErrorMessage(any(String.classs));

Categories

Resources