Mocking Annotations
Mocking annotations allow fine grained control over what mocking should be preferred when testing.
Using @InTestsMock
@InTestsMock
Perhaps you have a method that Diffblue Cover would ordinarily test using an Integer
but you'd prefer to see it tested using Mockito.mock(..)
. In this case you could annotate the method (or class, or package) to recommend mocking Number
:
public class ClassUnderTest {
@InTestsMock(Number.class)
public static String methodUnderTest(Number number) {
return String.valueOf(number.intValue());
}
}
Setting the priority of the annotation
There are various levels of priority that can be specified for the @InTestMock
annotation. The enum MockDecision
is provided by the Diffblue Cover Annotation library and can be set to the following values for the `decision' attribute. This attribute is optional and will default to MockDecision.RECOMMENDED
if unset.
MockDecision.REQUIRED
The class will be mocked at the highest priority, non-mocks may be provided if they provide more coverage.
MockDecision.RECOMMENDED
(default)
The class should be mocked at a high priority, non-mocks may be provided if they provide more coverage.
MockDecision.ALLOWED
Diffblue Cover will try to create an instance of the class itself, if it is unable to, Diffblue Cover will fallback to mock it.
MockDecision.FORBIDDEN
Diffblue Cover will not try to mock this class.
For example, if Diffblue Cover normally mocks a particular class, but there is a specific location where it should not do so, you can forbid mocking in that location.
public class ClassUnderTest {
@InTestsMock(value = Number.class, decision = MockDecision.FORBIDDEN)
public static String methodUnderTest(Number number) {
return String.valueOf(number.intValue());
}
}
Suggesting values to return
When mocking a class, it can be useful to provide Diffblue Cover with suggested values that each method can return. This can be achieved using the following (optional) attributes:
method
The simple name of the method to mock
method = "intValue"
booleanReturnValues
The boolean value (or an array of values) to return
booleanReturnValues = true
or booleanReturnValues = {true,false}
byteReturnValues
The byte value (or an array of values) to return
byteReturnValues = (byte) 1
or byteReturnValues = {(byte) 1,(byte) 0}
charReturnValues
The char value (or an array of values) to return
charReturnValues = 'A'
or charReturnValues = {'A','B'}
intReturnValues
The int value (or an array of values) to return
intReturnValues = 2
or intReturnValues = {2,3}
shortReturnValues
The short value (or an array of values) to return
shortReturnValues = 3
or shortReturnValues = {3,4}
longReturnValues
The long value (or an array of values) to return
longReturnValues = 4L
or longReturnValues = {4L,5L}
floatReturnValues
The float value (or an array of values) to return
floatReturnValues = 5.0f
or floatReturnValues = {5.0f,6.0f}
doubleReturnValues
The double value (or an array of values) to return
doubleReturnValues = 6.0d
or doubleReturnValues = {6.0d,7.0d}
stringReturnValues
The String value (or an array of values) to return
stringReturnValues = "AAA"
or stringReturnValues = {"AAA","BBB"}
returnValueFactory
The name of the static method to call to create the required object. The syntax is: fully qualified class name + method name, separated by a dot
returnValueFactory = "com.example.Factory.makeUser"
throwException
The class of the exception to throw when the method is called. Must be a subclass of Throwable
with an accessible constructor.
throwException = IllegalArgumentException.class
throwExceptionFactory
The name of the static method to call to create the exception instance. The syntax is: fully qualified class name + method name, separated by a dot. The method must return a subclass of Throwable
throwExceptionFactory= "com.example.Factory.createCustomException"
For example, to suggest that Diffblue Cover should return a value of 5
from the mocked method Number.intValue()
, the following annotation could be used:
public class ClassUnderTest {
@InTestsMock(value = Number.class, method = "intValue", intReturnValues = "5")
public static String methodUnderTest(Number number) {
return String.valueOf(number.intValue());
}
}
To return an object, use a factory method. Diffblue Cover will call the specified static method and use its result as the mocked return value.
public class ClassUnderTest {
@InTestsMock(
value = AccountService.class,
method = "getAccount",
returnValueFactory = "com.example.Factory.createTestAccount"
)
public static String methodUnderTest(AccountService service) {
return service.getAccount().getId();
}
}
Suggesting an array of values
Since a mocked method can only return a single value, why specify an array of values? Diffblue Cover will try to use the values in the order they are specified. The value chosen is the value that provides the best test. In most cases, specifying only a single value will be sufficient for generating a test with good coverage. Not all provided values will be used if Diffblue Cover has already generated a test with good coverage.
Using multiple @InTestsMock
annotations
@InTestsMock
annotationsYou can specify multiple mocked methods by using the annotation more than once:
@InTestsMock(
value = UserService.class,
method = "getName",
stringReturnValues = {"Alice"}
)
@InTestsMock(
value = UserService.class,
method = "getAge",
intReturnValues = {30}
)
@InTestsMock(
value = AccountService.class,
method = "getAccount",
returnValueFactory = "com.example.Factory.createTestAccount"
)
public boolean isValid(UserService user, AccountService account) {
return user.getName().length() >= 3
&& user.getAge() >= 18
&& account.getAccount().getId().startsWith("test-");
}
Precedence when using multiple annotations
When multiple @InTestsMock
annotations are applied to the same method under test there are a few aspects to understand regarding how Diffblue Cover will utilize the annotations:
Diffblue Cover will always favor the annotation nearest the method under test. This allows you to define an annotation at the class level, which will affect all methods in the class, and then override specific methods by defining an annotation at the method level.
The
MockDecision
('decision') is applied to theClass
('value').If the 'decision' is
MockDecision.FORBIDDEN
then the values of 'method' and '*returnValues' are ignored.
The various 'returnValues' and 'throwException' attributes are applied to the combination of 'value' (i.e.
Class
) and 'method', and aggregate for aClass#Method
combination.
Please see the below illustration:
@InTestsMock(
value = AccountService.class,
decision = MockDecision.FORBIDDEN,
method = "getBalance",// This value will be ignored as decision is FORBIDDEN
intReturnValues = {5} // This value will be ignored as decision is FORBIDDEN
)
@InTestsMock(
value = UserService.class,
decision = MockDecision.ALLOWED,
method = "getName",
stringReturnValues = {"Alice"}
)
public class ClassUnderTest {
@InTestsMock(
value = UserService.class,
method = "getName",
stringReturnValues = {"Bob", "Janice"} // In addition to the class level value
)
@InTestsMock(
value = UserService.class,
decision = MockDecision.REQUIRED,
// mocking UserService will be given the highest priority
method = "getAge",
intReturnValues = {30}
)
@InTestsMock(
value = AccountService.class,
// No defined 'decision', AccountService mocking will be RECOMMENDED
method = "getAccount",
returnValueFactory = "com.example.Factory.createTestAccount"
)
public boolean isValid(UserService user, AccountService account) {
return user.getName().length() >= 3
&& user.getAge() >= 18
&& account.getAccount().getId().startsWith("test-")
&& account.getBalance() >= 0;
}
}
In the example above, Diffblue Cover will configure how it generates mock objects when writing tests for ClassUnderTest#isValid
in the following way:
When generating a
UserService
object Diffblue Cover will useMockDecision.REQUIRED
When mocking method
UserService#getName
, suggested values "Bob", "Janice" and "Alice" are provided.When mocking method
UserService#getAge
, suggested value 30 is provided.
AccountService will use
MockDecision.RECOMMENDED
When mocking method
AccountService#getBalance
, mock will be configured to return Diffblue Cover generated values.When mocking method
AccountService#getAccount
, suggested object factorycom.example.Factory.createTestAccount
is provided.
Using @InTestsMockConstruction
@InTestsMockConstruction
Perhaps you have a method that Diffblue Cover is unable to test, and you think it could make more progress using Mockito.mockConstruction(Random.class)
. In this case, you could annotate the method (or class, or package) to recommend mocking construction of Random
:
public class ClassUnderTest {
@InTestsMockConstruction(Random.class)
public static int methodUnderTest() {
return new Random().nextInt();
}
}
Using @InTestsMockStatic
@InTestsMockStatic
Perhaps you have a method that Diffblue Cover is unable to test, and you think it could make more progress using Mockito.mockStatic(UUID.class)
. In this case, you could annotate the method (or class, or package) to recommend mocking static methods of UUID
:
public class ClassUnderTest {
@InTestsMockStatic(UUID.class)
public static Path methodUnderTest() {
return Paths.get(UUID.randomUUID() + ".zip");
}
}
Last updated
Was this helpful?