Java – mockito style anyxxx unit test method
When unit testing some methods, some situations may occur. The value of some parameters is not important and can be any value
For example, in this Code:
public void method(String arg1,String arg2,int arg3){ if(arg1 == null) throw new NullPointerException("arg1 is null"); //some other code }
When arg1 is null, NPE must be thrown. The values of other parameters are unimportant. They can be any value or empty
So I want to record the fact that these values are irrelevant to the method under test
I thought of the following options:
Option 1: define any_ Constant of XXX
I want to explicitly create the constant any_ String and any_ Int, which contains a fixed value, records that it can be any value, and the measured method does not care about the actual value
I can put all these constants in a class named any and reuse them in all test classes
Option 2: any_ Random value of XXX
This option seems a bit of a hacker to me because I've read somewhere that randomness should not be brought into test cases But in this case, this randomness will not be visible because the parameter will not have any side effects
Which method is more suitable for better, readable testing?
to update:
Although I can use any by defining constants in the any class_ XXX method, but I'm also considering using some constraints to generate any_ XXX value, for example
Any.anyInteger().nonnegative(); Any.anyInteger().negative(); Any.anyString().thatStartsWith("ab");
I think maybe hamcrest matchers can be used to create this link But I don't know if it's good Similar methods of anyobject () have been provided by mockito, but these methods are only applicable to mocks and spies, not ordinary objects I want to implement the same more readability tests for normal objects
Why?
Suppose I have a class
class MyObject{ public MyObject(int param1,Object param2){ if(param1 < 0) throw new IllegalArgumentException(); if(param2 == null) throw new NullPointerException(); } }
Now when writing the test constructor
class MyObjectTest{ @Test(expected=NullPointerException.class) public void testConstructor_ShouldThrowNullpointer_IfSecondParamIsNull(){ //emphasizing the fact that value of first parameter has no relationship with result,for better test readability new MyObject(Any.anyInteger().nonnegative(),null); } }
Solution
My preference is to establish a utility class constant and method to help create the constant value of the test, for example:
public final class Values { public static final int ANY_INT = randomInt(Integer.MIN_VALUE,Integer.MAX_VALUE); public static final int ANY_POSITIVE_INT = randomInt(0,Integer.MAX_VALUE); public static final String ANY_ISBN = randomIsbn(); // etc... public static int randomInt(int min,int max) { /* omitted */ } public static String randomIsbn() { /* omitted */ } // etc... }
Then I will use static import to pull the constants and methods required by a specific test class
I only use any if I don't care about the value_ Constants, I found that they can make the test intention clearer, for example:
// when service.fooBar(ANY_INT,ANY_INT,5);
Obviously, a value of 5 has some meaning - although it would be better as a local variable
Utility methods can be used to automatically generate values when setting up tests, for example:
// given final String isbn1 = randomIsbn(); final String isbn2 = randomIsbn(); final Book[] books = { new Book(isbn1),new Book(isbn2) }; // when bookRepository.store(books);
Again, this can help test courses care about the test itself rather than about data settings
In addition, I also used similar methods from domain objects When you combine these two methods, it can be very powerful For example:
public final class Domain { public static Book book() { return new Book(randomIsbn()); } // etc... }