I am unit testing a Spring Boot service method. I have a void method with no args. It queries a db and gets a List. I can mock and assert on that. Then it runs through the list and changes object fields according to some condition. How can I check the contents of that list so I can assert on them?
#Transactional
public void someMethod() {
List<Person> myList = repository.findAllByAge(0);
myList.forEach(person -> person.setAge(18));
}
How can I assert on myList to check that each Person in myList with age 0 is getting set to age 18? I currently have this in my test class...
#Test
public void someMethod_withSuccess() {
List<Person> testList = new ArrayList<>();
testList.add(toPersonEntity(createPersonDto().setAge(0)));
when(mockRepo.findAllByAge(0)).thenReturn(testList);
mockService.someMethod();
}
You can call that method through Reflection API.
btw, if you need to test this method, it probably has to be redisigned to be public or not tested at all.
it is as easy as this
testList.forEach(person -> assertThat("person "+testList.indexOf(person),person.getAge(),equalTo(28)));
Related
Hello I am fairly new to unit testing with Junit as well as Mockito. I think I have a fairly reasonable understanding of the principles but I can't seem to find any explanations of what I am specifically trying to test online.
I want to test a method, that calls several other methods (void and non-void), which also instantiates objects in the method body. I unfortunately cannot share the code as it is not mine, but here is a general format:
class classToTest {
private final field_1;
public void methodToTest( string id, List object_1, List object_2) {
try {
Map<SomeObject_1, SomeObject_2> sampleMap = new HashMap<>();
method_1(object_1, object_2); //void function modifies object_2
field_1.method_2(id, object_2);
Map<SomObeject_1, List<object>> groupedList = groupList(object_2)
//Then some stuff is added to the sampleMap
}
//catch would be here
}
At the moment I only care about testing method_1, and I cannot test directly as it is a private method so I must go through this parent method call. I wish I could change the code but I have been asked to keep it the same and to test in this manner with Mockito and Junit.
I know I need to Mock an object of the class to Test as well as its parameter:
private classToTest classToTestObject;
#Mock private field_1 f1;
#Before
public void setup() {
MockitoAnnotations.init.Mocks(this);
classToTestObject = mock(classToTest.class, CALLS_REAL_METHODS);
}
but I don't know where to start my actual test, as in how I can essentially just execute that one method call and ignore all the rest. I can't just not ignore the other objects and method calls either as the main method will throw exceptions if they are not handled correctly.
Any help and guidance is much appreciated, sorry that I could not share the code. Thank You!
At the moment I only care about testing method_1, and I cannot test directly as it is a private method so I must go through this parent method call.
Per your comment, and the note in your code:
method_1(object_1, object_2); //void function modifies object_2
You would set up a test that allows you to verify the expected final state of object_2. You would do this with a real instance of the class, not a mock.
#Test
public void method1Test() {
// Assemble - your preconditions
ClassToTest subject = new ClassToTest();
List<SomeType> object_1 = new ArrayList();
List<SomeOtherType> object_2 = new ArrayList();
// Populate object_1 and object_2 with data to use as input
// that won't throw exceptions. Call any methods on subject that put
// it in the desired state
// Act - call the method that calls the method under test
subject.methodToTest("some id that makes the method run correctly", object_1, object_2);
// Assert - one or more assertions against the expected final state of object_2
assertThat(object_2).matchesYourExpectations();
}
How to mock methods with void return type?
I implemented an observer pattern but I can't mock it with Mockito because I don't know how.
And I tried to find an example on the Internet but didn't succeed.
My class looks like this:
public class World {
List<Listener> listeners;
void addListener(Listener item) {
listeners.add(item);
}
void doAction(Action goal,Object obj) {
setState("i received");
goal.doAction(obj);
setState("i finished");
}
private string state;
//setter getter state
}
public class WorldTest implements Listener {
#Test public void word{
World w= mock(World.class);
w.addListener(this);
...
...
}
}
interface Listener {
void doAction();
}
The system is not triggered with mock.
I want to show the above-mentioned system state. And make assertions according to them.
Take a look at the Mockito API docs. As the linked document mentions (Point # 12) you can use any of the doThrow(),doAnswer(),doNothing(),doReturn() family of methods from Mockito framework to mock void methods.
For example,
Mockito.doThrow(new Exception()).when(instance).methodName();
or if you want to combine it with follow-up behavior,
Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();
Presuming that you are looking at mocking the setter setState(String s) in the class World below is the code uses doAnswer method to mock the setState.
World mockWorld = mock(World.class);
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
System.out.println("called with arguments: " + Arrays.toString(args));
return null;
}
}).when(mockWorld).setState(anyString());
I think I've found a simpler answer to that question, to call the real method for just one method (even if it has a void return) you can do this:
Mockito.doCallRealMethod().when(<objectInstance>).<method>();
<objectInstance>.<method>();
Or, you could call the real method for all methods of that class, doing this:
<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);
Adding to what #sateesh said, when you just want to mock a void method in order to prevent the test from calling it, you could use a Spy this way:
World world = new World();
World spy = Mockito.spy(world);
Mockito.doNothing().when(spy).methodToMock();
When you want to run your test, make sure you call the method in test on the spy object and not on the world object. For example:
assertEquals(0, spy.methodToTestThatShouldReturnZero());
The solution of so-called problem is to use a spy Mockito.spy(...) instead of a mock Mockito.mock(..).
Spy enables us to partial mocking. Mockito is good at this matter. Because you have class which is not complete, in this way you mock some required place in this class.
First of all: you should always import mockito static, this way the code will be much more readable (and intuitive):
import static org.mockito.Mockito.*;
For partial mocking and still keeping original functionality on the rest mockito offers "Spy".
You can use it as follows:
private World world = spy(new World());
To eliminate a method from being executed you could use something like this:
doNothing().when(someObject).someMethod(anyObject());
to give some custom behaviour to a method use "when" with an "thenReturn":
doReturn("something").when(this.world).someMethod(anyObject());
For more examples please find the excellent mockito samples in the doc.
How to mock void methods with mockito - there are two options:
doAnswer - If we want our mocked void method to do something (mock the behavior despite being void).
doThrow - Then there is Mockito.doThrow() if you want to throw an exception from the mocked void method.
Following is an example of how to use it (not an ideal usecase but just wanted to illustrate the basic usage).
#Test
public void testUpdate() {
doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] arguments = invocation.getArguments();
if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) {
Customer customer = (Customer) arguments[0];
String email = (String) arguments[1];
customer.setEmail(email);
}
return null;
}
}).when(daoMock).updateEmail(any(Customer.class), any(String.class));
// calling the method under test
Customer customer = service.changeEmail("old#test.com", "new#test.com");
//some asserts
assertThat(customer, is(notNullValue()));
assertThat(customer.getEmail(), is(equalTo("new#test.com")));
}
#Test(expected = RuntimeException.class)
public void testUpdate_throwsException() {
doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class));
// calling the method under test
Customer customer = service.changeEmail("old#test.com", "new#test.com");
}
}
You could find more details on how to mock and test void methods with Mockito in my post How to mock with Mockito (A comprehensive guide with examples)
In Java 8 this can be made a little cleaner, assuming you have a static import for org.mockito.Mockito.doAnswer:
doAnswer(i -> {
// Do stuff with i.getArguments() here
return null;
}).when(*mock*).*method*(*methodArguments*);
The return null; is important and without it the compile will fail with some fairly obscure errors as it won't be able to find a suitable override for doAnswer.
For example an ExecutorService that just immediately executes any Runnable passed to execute() could be implemented using:
doAnswer(i -> {
((Runnable) i.getArguments()[0]).run();
return null;
}).when(executor).execute(any());
Adding another answer to the bunch (no pun intended)...
You do need to call the doAnswer method if you can't\don't want to use spy's. However, you don't necessarily need to roll your own Answer. There are several default implementations. Notably, CallsRealMethods.
In practice, it looks something like this:
doAnswer(new CallsRealMethods()).when(mock)
.voidMethod(any(SomeParamClass.class));
Or:
doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock)
.voidMethod(any(SomeParamClass.class));
I think your problems are due to your test structure. I've found it difficult to mix mocking with the traditional method of implementing interfaces in the test class (as you've done here).
If you implement the listener as a Mock you can then verify the interaction.
Listener listener = mock(Listener.class);
w.addListener(listener);
world.doAction(..);
verify(listener).doAction();
This should satisfy you that the 'World' is doing the right thing.
If you need to do some operations in the mocked void method, and you need to manipulate the argument that sent to void method; you can combine Mockito.doAnswer with ArgumentCaptor.capture method.
Let's say you have SpaceService that autowires a GalaxyService, which has a void method called someServiceMethod.
You want to write test for one of your method in SpaceService that calls GalaxyService's void method. Your planet is also generated inside SpaceService. So you don't have any chance to mock that.
Here is your sample SpaceService class that you want to write tests for.
class SpaceService {
#Autowired
private GalaxyService galaxyService;
public Date someCoolSpaceServiceMethod() {
// does something
Planet planet = new World();
galaxyService.someServiceMethod(planet); //Planet updated in this method.
return planet.getCurrentTime();
}
}
The GalaxyService.someServiceMethod method expects a planet argument. Does some stuff in the method. See :
GalaxyService {
public void someServiceMethod(Planet planet) {
//do fancy stuff here. about solar system etc.
planet.setTime(someCalculatedTime); // the thing that we want to test.
// some more stuff.
}
}
And you want to test this feature.
Here is an example :
ArgumentCaptor<World> worldCaptor = ArgumentCaptor.forClass(World.class);
Date testDate = new Date();
Mockito.doAnswer(mocked-> {
World capturedWorld = worldCaptor.getValue();
world.updateTime(testDate);
return null;
}).when(galaxyService.someServiceMethod(worldCaptor.capture());
Date result = spaceService.someCoolSpaceServiceMethod();
assertEquals(result, testDate);
In your example you should mock Listener item and use Mockito.verify to check interactions with it
I was writing a Junit to test a scenario where an object changes its variables and saves it into the database 2 times. The argumentCaptor is invoked in save operation. The getAllValues() is returning two records. But both values are referenced to the same last capture record.
ImplimentationClass.java
...
myObj.setVariable(oneValue);
saveMyObj(myObj);
myObj.setVariable(otherValue);
saveMyObj(myObj);
...
saveMyObj(MyObject myObj){
repository.save(myObj);
}
ImplimentationClassTest.java
private ImplimentationClass underTest ;
#Mock
private Repository mockRepository;
#Before
public void setup(){
initMocks(this);
underTest = new ImplimentationClassTest();
}
#Test
public void test(){
ArgumentCaptor<MyObject> captor = ArgumentCaptor.forClass(MyObject.class);
MyObject obj = new MyObject(value);
underTest.implementedMethod(obj);
verify(mockRepository, times(2)).save(captor.capture());
assertEquals(oneValue, captor.getAllValues().get(0).getVariable()); //failing here -getting otherValue
assertEquals(otherValue, captor.getAllValues().get(1).getVariable());
}
Any idea how to capture same object multiple times?
The problem from your test originates from this piece of code.
myObj.setVariable(oneValue);
saveMyObj(myObj);
myObj.setVariable(otherValue);
saveMyObj(myObj);
Once you change the variable inside of myObj you change it for all references. Note that the ArgumentCaptor does not make a deep copy of myObj.
So you will end up with two references to myObj, which only has the latest state.
To avoid this you might want to pass a different instance to the second call.
Another alternative might be to use doAnswer instead and check the correctness of the paramter inside that method.
Check this answer for an example.
I have a JUnit test as:
#Spy
ParallelSender parallelSender = new ParallelSender();
#Test
public void send() {
// making some data...
parallelSender.send(someData);
// check that internal method has been called with Sender Task made from someData
verify(parallelSender).doSend(any(SenderTask.class));
}
I however like to examine that SenderTask contains all the fields exactly as I need them. Can I tell the spy to intercept the doSend call, store its parameters in some array and then continue to real method?
Use the ArgumentCaptor:
#Test
public void send() {
// making some data...
parallelSender.send(someData);
// Define the captor for class
ArgumentCaptor<SenderTask> captor =
ArgumentCaptor.forClass(SenderTask.class);
// Capture input while verifying
verify(parallelSender).doSend(captor.capture());
// Assert
SomeTask result = captor.getValue();
// assertions on result
}
You can use an ArgumentCaptor.
#Captor
ArgumentCaptor<SenderTask> captor;
// or ArgumentCaptor<SenderTask> captor =
// ArgumentCaptor.forClass(SenderTask.class);
#Test public void send() {
// ...
verify(parallelSender).doSend(captor.capture());
SenderTask captured = captor.getValue();
I rarely use argument captor because it's usually not necessary.
Just do this
#Test
public void send() {
//given
SomeData myInput = ...
SenderTask expectedOutput = new SenderTask();
expectedOutput.setSomeField(/*expected field value*/);
//when
parallelSender.send(myInput);
//then
verify(parallelSender).doSend(expectedOutput);
}
The idea behind is to check that "doSend" was called with an expected object.
Note: just make sure that you implemented equals/hash method in SenderTask - or it will not work
Note2: I would suggest avoiding using any() in your unit tests. Usually when your are unit-testing something - you want to be as much precise as possible. So use concrete objects during results verification.
Hopefully it helps
I have the following code, where each url in listOne is tested with the method testItem:
#Parameters(name="{0}")
public static Collection<Object[]> data() throws Exception {
final Set<String> listOne = getListOne();
final Collection<Object[]> data = new ArrayList<>();
for (final String url : listOne) {
data.add(new Object[] { url });
}
return data;
}
#Test
public void testItem() {
driverOne.makeDecision(urlToTest);
assertTrue(driverOne.success(urlToTest);
}
What if I now wanted to add a second list, listTwo, and run a test method defined as follows on JUST the items of listTwo (but not listOne?)
#Test
public void testItemAlternate() {
driverTwo.makeDecision(urlToTest);
assertTrue(driverTwo.success(urlToTest));
}
That is, I want driverOne to make the decision for all URLs in listOne, and I want driverTwo to make the decision for all URLs in listTwo. What is the best way to translate this to code? Thanks.
Cited from: https://github.com/junit-team/junit/wiki/Parameterized-tests
The custom runner Parameterized implements parameterized tests. When running a parameterized test class, instances are created for the cross-product of the test methods and the test data elements.
Thus, I assume No, that's not possible.
If you want to do such a thing I guess that you either
(1) will need to construct two test classes one for each test to be executed with the first collection and one for each test to be executed with the second collection or
(2) will need to use another mechanism besides the #Parameters annotation, maybe hand-crafted.
You could include some test set identifier in your test set data itself, and then use the org.junit.Assume class to help:
#Test
public void testItem() {
org.junit.Assume.assumeTrue(testSetId.equals("TEST_SET_1"));
driverOne.makeDecision(urlToTest);
assertTrue(driverOne.success(urlToTest);
}
#Test
public void testItemAlternate() {
org.junit.Assume.assumeTrue(testSetId.equals("TEST_SET_2"));
driverTwo.makeDecision(urlToTest);
assertTrue(driverTwo.success(urlToTest));
}
As a completely different answer, there exists junit-dataprovider