How do I get Mockito to mock a constant from another file? - java

EDIT: The method I'm testing calls this constant that's defined in another class, so I want to test that th emethod works independently of how the other class defines the constant. Mocking it was the first thing I could think of, but I'm open to other ideas for how to test it in a clean, secure way
(Class, method, and variable names are genericized)
I'm trying to figure out how to write a test.
One of my methods gets a constant from another class, like so:
OtherClass.CONSTANT
and this constant is defined as:
public static final List<Long> CONSTANT =
ImmutableList.of(1, 2);
In the test for this method, I want to mock this call. I've tried
when(OtherClass.CONSTANT).thenReturn(ImmutableList.of(1, 2));
but that gives me this error:
RegularImmutableList cannot be returned by otherFunction()
otherFunction() should return String
otherFunction() being some other function in the code base that doesn't seem to be related to anything I've been working on.
I've also tried
doReturn(ImmutableList.of(1, 2)).when(OtherClass.CONSTANT);
but, as you might be guessing, it gives me this error:
Argument passed to when() is not a mock!
Example of correct stubbing:
doThrow(new RuntimeException()).when(mock).someMethod();
I'm pretty lost as to how exactly I should be mocking this constant.

As you've discovered, you can't mock the value of a constant.
Likely the easiest method would be to convert your design to use an interface to supply the value, rather than using the value directly.
Something like:
interface ConstantSupplier {
List<Long> get();
}
public MyClass(ConstantSupplier supplier) {
this.supplier = supplier;
}
Then you would replace references to the constant to supplier.get().
This is now easy to mock:
ConstantSupplier supplier = mock(ConstantSupplier.class);
when(supplier.get()).thenReturn(List.of(4L, 9L));
Your non-mocked code could use a lambda to supply the real value:
obj = new MyClass(() -> OtherClass.CONSTANT);

Related

Mockito: verify arguments passed to new

I'm trying to work out how to verify the parameters passed to a mocked constructor in Mockito. A simplified version of my code is:
class Mocked {
Mocked(String first, String second, int value) {
}
}
class Target {
void testMe() {
new Mocked("Hello", "World", 99);
}
}
#Test
public void test_Target() {
try (
MockedConstruction<Mocked> mockedNew = mockConstruction(Mocked.class);
) {
new Target().testMe();
Mocked mocked = mockedNew.constructed().get(0);
// TODO: verify all arguments passed to mocked
}
}
The class I'm trying to test is "Target"
Target uses an instance of the "Mocked" class. In real code code I'll want to use an actual instance of Mocked, but for the purposes of testing I want to mock it out so I can test "Target" in isolation of "Mocked". I've used the mockConstruction construct to do this.
In my final version of my code the arguments passed to the Mocked constructor are not hardcoded. Instead there will be some business logic to derive them, so and I want to verify they have been derived out correctly. But how?
None of the examples I've Googled show show me how to do this, and org.mockito.Mockito.verify() doesn't appear to have a way to test a constructor.
The only solution I can see is to add mock initialiser function that copies the argument into local variables. But this involves making those variables effectively final (so final one element array) and ugly casts. Surely there has to be something better than that!
What have I missed?
As far as I know, this is not possible using the Mockito API.
You can try a design change where a new MockedFactory class is responsible for creating Mocked objects. You can create a MockMockedFactory for your tests and inject it into Target to use. You will be able to verify the methods called on this factory by the class under test. Not the nicest, adds boilerplate code, but works.
Also, I guess the newly created object is not returned as testing would not be a problem then. It is worth considering if the method you are testing isn't too big doing too many things at once. Maybe some other refactors could help make it more testable.
Or maybe this one: https://groups.google.com/g/mockito/c/WqPlcNrvbOw?pli=1

Test lambda expressions called by dependencies

I am trying to test some code inside lambda expression which is a call back from another class.
class EmailSender {
private EmailBuilder emailBuilder;
public void send() {
String testEmail = emailBuilder.buildEmail("Test Email", bodyContentAppender());
//send testEmail
}
private Consumer<Email> bodyContentAppender() {
//how to test this through JUnit?
return email -> email.appendBody("Body Content");
}
}
interface EmailBuilder {
String buildEmail(String templateName, Consumer<Email> contentAppender);
}
The lambda expression in the method getBodyContent is called from EmailBuilder which is a mocked dependency in the JUnit test for EmailSender. Since I am mocking the behavior of EmailBuilder, the code inside getBodyContentis not called from tests. How to test such piece?
EDIT:
Capturing the lambda expression through Argument Captors is not a solution in this case as the behavior of EmailBuilder is mocked and the actual methods are not called. Secondly, email.appendBody does some transformations on an object which is passed by an external API and not straightforward to create.
What you are trying to do here is essentially to verify that a factory method did in fact really return the correct object. There is this related question, where the consensus is to not test the result of a factory method beyond verifying that it does indeed return an object of the correct type. The behavior of that object should be tested in the UnitTests for that type.
In an answer to this related question on unit testing lambdas Stuart Marks argues that
If the code in the lambda is complex enough that it warrants testing, maybe that code ought to be refactored out of the lambda, so that it can be tested using the usual techniques.
Now, the real question is: If this was not a lambda, but a concrete class MyBodyContentAppender that implements the functional interface Consumer<Email>, how would you unit test that? What kinds of test would you write for this class?
You would probably write tests to verify that, given an Email, invoking accept() does indeed invoke appendBody() with the appropriate parameters, perhaps that invoking it with a null argument throws a NullPointerException etc. You would possibly not verify that email.appendBody() works as expected, because that is covered by the tests for Email. You may have to mock Email for these tests if it is difficult to create.
Well, all of these tests can also be performed for the lambda. Your problem is that the factory and the type of the created object are both private, so from the perspective of your test, the only way to access that object is via the parameter passed to the (mocked) emailBuilder.buildEmail().
If you use Mockito for mocking the emailBuilder, you could capture the arguments to this method via ArgumentCaptors (see 15. Capturing arguments for further assertions (Since 1.8.0)), I'm sure other mocking libraries provide similar functionality.
Most mocking frameworks allow you to check arguments that are used when invoking methods on mocked object. Respectively, you can capture them.
So:
acquire the parameter passed
simply invoke the "code" that it represents, and check if that makes the expected updates to an Email object you provided.
It will be easier to test if you actually supply the body content as an argument, and make sure the method is public. If you intend to keep the method as private, then you should test the public method calling it.
public Consumer<Email> getBodyContent(String body) {
//how to test this through JUnit?
return email -> email.appendBody(body);
}
Then you can test it as
#Test
public void testGetBodyContent(){
.... //send different arguments and assert
....
}
So when you want to unit test your code you must ensure that it's doing one job at a time. You method is named as getBodyContent but seems like is supposed to do no more work than appending to email body. Hence, you could pull out this method to be public.
Now you could pass the body and get the content.
#Test
public void testGetBodyContent(){
consumer<Email> consumer = EmailSender.getBodyContent();
assertEquals("Email Content", consumer.accept(<mocked Email object>).getBody())
}

mockito when with third party class

I need to use a third party class in Mockito.when as parameter. The class does not have equals implementation and hence Mockito.when always returns null except the case where any() is used.
The below always returns null:
when(obj.process(new ThirdParytClass())).thenReturn(someObj);
however, this works
when(obj.process(any(ThirdParytClass.class))).thenReturn(someObj);
But, the problem is the process() method is called twice in the actual code and the use of any() is ambiguous and does not help in covering the multiple scenarios to test.
Extending the class does not help and also leads to other complications.
Is there a way to address the issue.
If a class doesn't implement a (sensible) equals(Object), you can always match instances yourself by implementing your own ArgumentMatcher. Java 8's functional interfaces make this pretty easy to write (not that it was such a big hardship in earlier versions, but still):
when(obj.process(argThat(tpc -> someLogic()))).thenReturn(someObj);
More often than not, however, if you just want to compare the class' data members, the built-in refEq matcher would do the trick:
ThirdParytClass expected = new ThirdParytClass();
// set the expected properties of expected
when(obj.process(refEq(expected))).thenReturn(someObj);
Mockito provides the captor feature that may help you to bypass limitations of equals() method because overriding equals() to make a test pass may be desirable but it is not always the case.
And besides, sometimes, equals() may not be overridable. It is your use case.
Here is a example code with an ArgumentCaptor :
#Mock
MyMockedClass myMock;
#Captor
ArgumentCaptor argCaptor;
#Test
public void yourTest() {
ThirdPartyClass myArgToPass = new ThirdPartyClass();
// call the object under test
...
//
Mockito.verify(myMock).process(argCaptor.capture());
// assert the value of the captor argument is the expected onoe
assertEquals(myArgToPass , argCaptor.getValue());
}

Mockito Mock a method call called twice

I am trying to use mockito to mock a method. However the class I am injecting mocks with calls the method twice while sending in two different objects of the same type, but depending the values in the object determine the output of the method.
So, for example, If I am trying to mock
public ArrayList<example> attemptToMock(testObject testing)
Lets sat type testObject has a string value in it.
So if the string value in testObject is "OK" then attemptToMock should output an array of two objects in it. If testObject string value is "NO" then the Array list sent out only has one Object.
How to I write a test to handle a call so that a class can call attemptToMock twice, within the same method, and I can mock out its output it so depending on the values within testObject. I can mock it to send out different arrays.
A few options:
Override equals and hashCode on your object (TestObject). This is only feasible if all of the values on your object are predictable, and may be more work than other solutions, but if you need to write equals and hashCode anyway (for Map and Set behavior, for example) this is a reasonable solution.
// Mockito compares with objects' equals(Object) methods by default.
when(collaborator.attemptToMock(object1)).thenReturn(array1);
when(collaborator.attemptToMock(object2)).thenReturn(array2);
Write a Hamcrest matcher and use that to match the arrays. This acts as a compact analogue to equals for a specific case, and is especially handy if you need to change behavior based on the same value in many tests.
public class IsATestObjectWithValue extends TypeSafeMatcher<TestObject> {
private final String expectedValue;
public IsATestObjectWithValue(String expectedValue) {
super(TestObject.class);
this.expectedValue = expectedValue;
}
#Override public void matchesSafely(TestObject object) {
// object will never be null, but object.value might.
return expectedValue.equals(object.value);
}
}
Now you can write an equivalent match as above:
when(collaborator.attemptToMock(argThat(new IsATestObjectWithValue("OK")))
.thenReturn(array1);
when(collaborator.attemptToMock(argThat(new IsATestObjectWithValue("NO")))
.thenReturn(array2);
Use an Answer, as wdf described. Anonymous inner Answers are common and pretty concise, and you get access to all of the arguments. This is especially good for one-off solutions, or if you want to explicitly and immediately fail the test if an invalid value (testObject.value) is passed in.
As a last resort, if the order of the calls is predictable, you can return multiple values in sequence.
when(collaborator.attemptToMock(any(TestObject.class)))
.thenReturn(array1).thenReturn(array2);
when(collaborator.attemptToMock(any(TestObject.class)))
.thenReturn(array1, array2); // equivalent
Either of the above lines will return array1 for the first call and array2 for the second call and all calls after it, regardless of the parameter. This solution will be much more brittle than your original question asks for--it'll fail if the call order changes, or if either of the calls is edited out or repeated--but is sometimes the most compact solution if the test is very temporary or if the order is absolutely fixed.
You can access the parameters passed into a mocked method invocation and vary the return value accordingly by using the Answer interface. See the answer to this question, and the docs for Answer.
Basically, the only weird/non-obvious thing going on here is that you have to downcast the parameters to the type you are expecting. So, in your case, if you are mocking a method that takes a single 'TestObject' parameter, then you'll have to do something like this inside of your 'answer' implementation:
Object[] args = invocation.getArguments();
TestObject testObj = (TestObject) args[0];
if ("OK".equals(testObj.value)) {
return new ArrayList(value1, value2);
} else if ("NO".equals(testObj.value)) {
return new ArrayList(singleObject);
}

mockito mock verify

//Let's import Mockito statically so that the code looks clearer
import static org.mockito.Mockito.*;
//mock creation
List mockedList = mock(List.class);
//using mock object
mockedList.add("one");
mockedList.clear();
//verification
verify(mockedList).add("one");
verify(mockedList).clear();
I don't understand what is the point of this construct? How does it help? How is it different from just calling the functions?
The documentation is rather thin.
Thank you
You wish to test that some method Foo of class A calls some method Bar on an object of class B. In other words, you're testing class A. During your test, you make a mock of class B. Then you pass this mock object to class A somehow (depending on how class A actually works). When your test runs the Foo method of class A, you are expecting the Bar method to get called on your mock of class B. By calling verify for the Bar method, after the test of the Foo method, you can check that the Foo method is actually working correctly - that it calls Bar.
When you do mockedList.add("one"); its performing the operation on the mocked object as same time it remembers your operation. So when you do verify(mockedList).add("one");, it verifies the add was called on mockedList with argument one.
Hope you get the difference.
the verify method of mockito is verify the method invoke times,if the invoke time is 1,we can omit this parameter, see the source code of Mockito Line 1473
public static <T> T verify(T mock) {
return MOCKITO_CORE.verify(mock, times(1));
}
so you code
verify(mockedList).add("one");
//is the same as
verify(mockedList,times(1)).add("one");
is indeed to verify the add method's executed once
Indeed in your example it's obvious, but main idea of verifying methods calls appear during real code testing - imagine that some code performs method call like:
class A{
....
service.doSomething(<some arguments>)
....
}
In order to test it you'll pass mock service object, but sometimes you want to verify particular arguments values passed for that call (or number of calls), so you'll use verify like in your example.

Categories