I have a command line tool that performs a DNS check. If the DNS check succeeds, the command proceeds with further tasks. I am trying to write unit tests for this using Mockito. Here's my code:
public class Command() {
// ....
void runCommand() {
// ..
dnsCheck(hostname, new InetAddressFactory());
// ..
// do other stuff after dnsCheck
}
void dnsCheck(String hostname, InetAddressFactory factory) {
// calls to verify hostname
}
}
I am using InetAddressFactory to mock a static implementation of the InetAddress class. Here's the code for the factory:
public class InetAddressFactory {
public InetAddress getByName(String host) throws UnknownHostException {
return InetAddress.getByName(host);
}
}
Here's my unit test case:
#RunWith(MockitoJUnitRunner.class)
public class CmdTest {
// many functional tests for dnsCheck
// here's the piece of code that is failing
// in this test I want to test the rest of the code (i.e. after dnsCheck)
#Test
void testPostDnsCheck() {
final Cmd cmd = spy(new Cmd());
// this line does not work, and it throws the exception below:
// tried using (InetAddressFactory) anyObject()
doNothing().when(cmd).dnsCheck(HOST, any(InetAddressFactory.class));
cmd.runCommand();
}
}
Exception on running testPostDnsCheck() test:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 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"));
Any input on how to solve this?
The error message outlines the solution. The line
doNothing().when(cmd).dnsCheck(HOST, any(InetAddressFactory.class))
uses one raw value and one matcher, when it's required to use either all raw values or all matchers. A correct version might read
doNothing().when(cmd).dnsCheck(eq(HOST), any(InetAddressFactory.class))
I had the same problem for a long time now, I often needed to mix Matchers and values and I never managed to do that with Mockito.... until recently !
I put the solution here hoping it will help someone even if this post is quite old.
It is clearly not possible to use Matchers AND values together in Mockito, but what if there was a Matcher accepting to compare a variable ? That would solve the problem... and in fact there is : eq
when(recommendedAccessor.searchRecommendedHolidaysProduct(eq(metas), any(List.class), any(HotelsBoardBasisType.class), any(Config.class)))
.thenReturn(recommendedResults);
In this example 'metas' is an existing list of values
It might help some one in the future: Mockito doesn't support mocking of 'final' methods (right now). It gave me the same InvalidUseOfMatchersException.
The solution for me was to put the part of the method that didn't have to be 'final' in a separate, accessible and overridable method.
Review the Mockito API for your use case.
May be helpful for somebody. Mocked method must be of mocked class, created with mock(MyService.class)
For my case, the exception was raised because I tried to mock a package-access method. When I changed the method access level from package to protected the exception went away. E.g. inside below Java class,
public class Foo {
String getName(String id) {
return mMap.get(id);
}
}
the method String getName(String id) has to be AT LEAST protected level so that the mocking mechanism (sub-classing) can work.
Inspite of using all the matchers, I was getting the same issue:
"org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
1 matchers expected, 3 recorded:"
It took me little while to figure this out that the method I was trying to mock was a static method of a class(say Xyz.class) which contains only static method and I forgot to write following line:
PowerMockito.mockStatic(Xyz.class);
May be it will help others as it may also be the cause of the issue.
Another option is to use a captor: https://www.baeldung.com/mockito-argumentcaptor
// assume deliver takes two values
#Captor
ArgumentCaptor<String> address; // declare before function call.
Mockito.verify(platform).deliver(address.capture(), any());
String value = address.getValue();
assertEquals(address == "some#thing.com");
Captors are especially useful if say one member of the object you want to capture could be a random ID and another is something you can validate against.
Do not use Mockito.anyXXXX(). Directly pass the value to the method parameter of same type.
Example:
A expected = new A(10);
String firstId = "10w";
String secondId = "20s";
String product = "Test";
String type = "type2";
Mockito.when(service.getTestData(firstId, secondId, product,type)).thenReturn(expected);
public class A{
int a ;
public A(int a) {
this.a = a;
}
}
Related
I have method:
public void loadPlatformDependencies() {
try {
dependenciesRepository.deleteAll();
dependenciesRepository.saveAll(pullLastDependencies());
publisher.publishEvent(new LoadedDependenciesEvent());
} catch (Exception e) {
LOGGER.error("Failed to load dependencies", e);
}
}
And I try to test it:
#Test
public void testLoadPlatformDependencies() {
ArgumentCaptor<Iterable<Dependency>> captor = ArgumentCaptor.forClass(Iterable.class);
when(dependenciesRepository.saveAll(captor.capture())).thenReturn(any(Iterable.class));
puller.loadPlatformDependencies();
verify(dependenciesRepository,times(1)).deleteAll();
verify(dependenciesRepository, times(1)).saveAll(any(Iterable.class));
verify(publisher,times(1)).publishEvent(any());
}
But there is a problem, that method pullLastDependencies() work incorect now. I have a mistake:
Invalid use of argument matchers!
0 matchers expectd, 1 recorded:
Method pullLastDependencies() returns List.
Can I test this method without a properly working method pullLastDependencies()? Or maybe I should test this method in another way?
You're using the captor in when() instead of verify().
And you're returning any() (which is just null) from your mocked method, instead of returning what you want this mock to return. if you don't care about what it returns because you don't use it, then return an empty iterable.
It should be
when(dependenciesRepository.saveAll(any()).thenReturn(Collections.emptyList());
puller.loadPlatformDependencies();
verify(dependenciesRepository).deleteAll();
verify(dependenciesRepository).saveAll(captor.capture());
I think the problem here is that you are using a matcher as a return value in
when(dependenciesRepository.saveAll(captor.capture())).thenReturn(any(Iterable.class));
You should use the matchers to "match" method parameters, and return another structure, like this:
when(dependenciesRepository.saveAll(anyIterable())).thenReturn(Collections.emptyList())
As long as your pullLastDependencies() method doesn't have another dependency, it should work.
Edit:
It seems that your pullLastDependencies() has some other dependencies, so you need to mock the call to it. You can achieve this by changing the visibility of the method during the test, so you can mock it, but keep in mind that this is not considered good pratice.
//making private method accessible
Method method = service.getClass().getDeclaredMethod("pullLastDependencies",params);
method .setAccessible(true);
when(pullLastDependencies()).thenReturn(Collections.emptyList())
I have the following set of methods in different classes:
#ParameterizedTest
#MethodSource("com.myapp.AppleProvider#getApplesDependingOnConditions")
public void testSomething(Apple apple) {
SomeContainer.getInstance().setApple(apple)
// ...
}
The problem is that I cannot avoid copy/pase of the following
name argument for each test call
The very first line of each test - SomeContainer.getInstance().setApple(apple)
I tried to use extension points - BeforeTestExecutionCallback and BeforeEachCallback, but they don't seem to have ability to get parameter with which they are being called.
According to https://github.com/junit-team/junit5/issues/1139 and https://github.com/junit-team/junit5/issues/944 it's not possible to access argument passed to test from extension points yet and parameterized tests don't work for BeforeEach callbacks.
So I'm basically looking for any workaround so that my test could look like:
#MyAwesomeTest
public void testSomething() {
// ...
}
Where #MyAwesomeTest encapsulates two annotations above.
What I've already found:
In extension points the following data is available: displayname, method or tags. If I pass argument into the each test method (though it's very undesirable) looks like I can rely on displayname since it'll reflect argument passed to the method call for a particular parameter.
I'm trying to find out whether there're any other ways without need to add argument into each method.
I think you could cheat to get most of the way there:
public static Stream<String> apples() {
return com.myapp.AppleProvider
.getApplesDependingOnConditions()
.stream()
.peek(apple -> SomeContainer.getInstance().setApple(apple))
.map(apple -> { /* convert to name string */ })
}
#ParameterizedTest
#MethodSource("apples")
public void testSomething(String name) {
// ...
}
This might sound like a very easy question but I am really struggling to archive the solution.
Normally I mock and match quite easily my arguments.
Now I am matching a method that is like this:
getAppFacebookClient(page, V2_11).publish(destination, JsonObject.class, parameters.asArray());
this is for a facebook application and the parameters is a list of a custom Object. the asArray[] method was created in the class and basically does something like this:
public Parameter[] asArray() {
return parameters.toArray(new Parameter[parameters.size()]);
}
and the Parameter of this return is of the type com.restfb.Parameter
So, I am basically doing this
when(client.publish(anyString(), eq(JsonObject.class), any(com.restfb.Parameter[].class))).thenReturn(result);
but seems like it is never taken and of course I cannot manipulate result,
Any idea how could I mock this kind of objects in a proper way?
I also tried the other way
doReturn(result).when(client).publish(anyString(), eq(JsonObject.class), any(com.restfb.Parameter[].class));
Your code is correct ... unless the publish uses varargs!
In such a case you need to use any() / anyVararg() matcher.
Consider:
#Mock Thingy testee;
interface Thingy {
int f(String... arg);
}
#Test
public void test() {
// given
// works only if signature is `f(String[] arg)`
// when(this.testee.f(Mockito.any(String[].class))).thenReturn(42);
when(this.testee.f(Mockito.any())).thenReturn(42); // anyVararg() is deprecated
// when
final int result = this.testee.f(new String[] { "hello", "world" });
// then
assertThat(result, comparesEqualTo(42));
// works only if signature is `f(String[] arg)`
// verify(this.testee).f(Mockito.any(String[].class));
verify(this.testee).f(Mockito.any());
}
I've just ran into a problem recently when a method in my service was called with wrong parameters. This caused some kind of outage, so I'm thinking about how to prevent that in the future.
So assuming that I have the following method:
public boolean doSomething(String param1, String param2);
I want to verify that each time this method is called (no matter where in my service), the param1 value is specific (e.g. only String1, String2 and String3 would be a valid parameter value for that.
Is there any technology/library/tool for that to verify this for instance in a unit test?
Update: as the accepted answer suggests, this is something that should not be covered through unit tests since unit tests are for behavioural testing. What would prevent the wrong call in the future is using Preconditions or just simple parameter check.
When possible you should leverage compile-time checks rather than deferring the tests to runtime. If there are only three legal values then perhaps param1 should be an enum rather than a String.
Unit tests are for verifying that a method behaves in a certain way. They treat the method like a black box and poke it from the outside. They don't help if you're concerned with how it is called. There you're inside the method and want to verify that the outside world is well-behaved. The way to do that is with run-time precondition checks at the start of the method.
public boolean doSomething(String param1, String param2) {
if (!Objects.equals(param1, "String1") &&
!Objects.equals(param1, "String2") &&
!Objects.equals(param1, "String3"))
{
throw IllegalArgumentException("param1 must be String1, 2, or 3");
}
...
}
Guava's Preconditions class can be helpful.
public boolean doSomething(String param1, String param2) {
Preconditions.checkArgument(
Objects.equals(param1, "String1") ||
Objects.equals(param1, "String2") ||
Objects.equals(param1, "String3"),
"param1 must be String1, 2, or 3"
);
...
}
Create an unit test that ensures that only some values are accepted by the method as param1 parameter at runtime.
Code a test with the two scenarios : valid and invalid cases.
For example in JUnit 5 :
#Test
public void doSomething(){
Assert.AssertTrue(new Foo().doSomething("String1", "anyValue");
Assert.AssertTrue(new Foo().doSomething("String2", "anyValue");
Assert.AssertTrue(new Foo().doSomething("String3", "anyValue");
}
#Test
public void doSomething_with_illegal_argument(){
Assert.assertThrows(IllegalArgumentException.class, () -> new Foo().doSomething("invalidValue", "anyValue"));
}
The test should fail as you actually don't guarantee that.
So then improve your actual implementation to make the test pass.
For example :
public boolean doSomething(String param1, String param2) {
if (!"String1".equals(param1) &&
!"String2".equals(param1) &&
!"String3".equals(param1) {
throw new IllegalArgumentException("param1 should be ...");
}
... // processing
}
I would add that a test unit cannot cover all failing cases if the failing cases are any String but 3 specific Strings : it makes millions of possibilities.
In your case I think that the best way to make your code more robust is using a bounded type as an enum. You could so define a enum that contains 3 values and provide a enum constructor with the String actually passed as a parameter.
It could look like :
public boolean doSomething(MyEnum param1Enum, String param2){
...
String param1 = param1Enum.getString();
}
I have a method that gets called twice, and I want to capture the argument of the second method call.
Here's what I've tried:
ArgumentCaptor<Foo> firstFooCaptor = ArgumentCaptor.forClass(Foo.class);
ArgumentCaptor<Foo> secondFooCaptor = ArgumentCaptor.forClass(Foo.class);
verify(mockBar).doSomething(firstFooCaptor.capture());
verify(mockBar).doSomething(secondFooCaptor.capture());
// then do some assertions on secondFooCaptor.getValue()
But I get a TooManyActualInvocations Exception, as Mockito thinks that doSomething should only be called once.
How can I verify the argument of the second call of doSomething?
I think it should be
verify(mockBar, times(2)).doSomething(...)
Sample from mockito javadoc:
ArgumentCaptor<Person> peopleCaptor = ArgumentCaptor.forClass(Person.class);
verify(mock, times(2)).doSomething(peopleCaptor.capture());
List<Person> capturedPeople = peopleCaptor.getAllValues();
assertEquals("John", capturedPeople.get(0).getName());
assertEquals("Jane", capturedPeople.get(1).getName());
Since Mockito 2.0 there's also possibility to use static method Matchers.argThat(ArgumentMatcher). With the help of Java 8 it is now much cleaner and more readable to write:
verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("OneSurname")));
verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("AnotherSurname")));
If you're tied to lower Java version there's also not-that-bad:
verify(mockBar).doSth(argThat(new ArgumentMatcher<Employee>() {
#Override
public boolean matches(Object emp) {
return ((Employee) emp).getSurname().equals("SomeSurname");
}
}));
Of course none of those can verify order of calls - for which you should use InOrder :
InOrder inOrder = inOrder(mockBar);
inOrder.verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("FirstSurname")));
inOrder.verify(mockBar).doSth(argThat((arg) -> arg.getSurname().equals("SecondSurname")));
Please take a look at mockito-java8 project which makes possible to make calls such as:
verify(mockBar).doSth(assertArg(arg -> assertThat(arg.getSurname()).isEqualTo("Surname")));
If you don't want to validate all the calls to doSomething(), only the last one, you can just use ArgumentCaptor.getValue(). According to the Mockito javadoc:
If the method was called multiple times then it returns the latest captured value
So this would work (assumes Foo has a method getName()):
ArgumentCaptor<Foo> fooCaptor = ArgumentCaptor.forClass(Foo.class);
verify(mockBar, times(2)).doSomething(fooCaptor.capture());
//getValue() contains value set in second call to doSomething()
assertEquals("2nd one", fooCaptor.getValue().getName());
You can also use #Captor annotated ArgumentCaptor. For example:
#Mock
List<String> mockedList;
#Captor
ArgumentCaptor<String> argCaptor;
#BeforeTest
public void init() {
//Initialize objects annotated with #Mock, #Captor and #Spy.
MockitoAnnotations.initMocks(this);
}
#Test
public void shouldCallAddMethodTwice() {
mockedList.add("one");
mockedList.add("two");
Mockito.verify(mockedList, times(2)).add(argCaptor.capture());
assertEquals("one", argCaptor.getAllValues().get(0));
assertEquals("two", argCaptor.getAllValues().get(1));
}
With Java 8's lambdas, a convenient way is to use
org.mockito.invocation.InvocationOnMock
when(client.deleteByQuery(anyString(), anyString())).then(invocationOnMock -> {
assertEquals("myCollection", invocationOnMock.getArgument(0));
assertThat(invocationOnMock.getArgument(1), Matchers.startsWith("id:"));
}
First of all: you should always import mockito static, this way the code will be much more readable (and intuitive) - the code samples below require it to work:
import static org.mockito.Mockito.*;
In the verify() method you can pass the ArgumentCaptor to assure execution in the test and the ArgumentCaptor to evaluate the arguments:
ArgumentCaptor<MyExampleClass> argument = ArgumentCaptor.forClass(MyExampleClass.class);
verify(yourmock, atleast(2)).myMethod(argument.capture());
List<MyExampleClass> passedArguments = argument.getAllValues();
for (MyExampleClass data : passedArguments){
//assertSometing ...
System.out.println(data.getFoo());
}
The list of all passed arguments during your test is accessible via the argument.getAllValues() method.
The single (last called) argument's value is accessible via the argument.getValue() for further manipulation / checking or whatever you wish to do.