How to Test a Void Method Using Junit And/Or Mockito

How to test a void method using JUnit and/or Mockito

What you trying to do is actually not the way to do it. You should test ONLY the XmlToCsv class and not the classes that are used by this class (DocumentBuilderFactory, DocumentBuilder, Document, StreamSource, Transformer, Source, Result).

There are now 2 ways you can go: The clean code way, or the dirty test way.

The best solution is that you have a dependency framework for the classes you use:

public class XmlToCsv {

@Inject
DocumentBuilderFactory factory;

@Inject
StreamSource stylesource;

@Inject
TransformerFactory transformerFactory;

public void xmlToCsv(String sourceXlsFile, String sourceCsvFile, String sourceXmlFile) throws Exception {

//define the files
File stylesheet = new File(sourceXlsFile);
File xmlSource = new File(sourceXmlFile);

//create the DocumentBuilder to parse the XML file
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(xmlSource);

//input the stylesheet to transform the XML to
StreamSource stylesource = new StreamSource(stylesheet);
Transformer transformer = transformerFactory.newInstance().newTransformer(stylesource);

//write a new output file using the stylesheet format
Source source = new DOMSource(document);
Result outputTarget = new StreamResult(new File(sourceCsvFile));
transformer.transform(source, outputTarget);

}
}

Testing now can be done by injecting mocks into the injectable fields:

@RunWith(MockitoJUnitRunner.class)
public class XmlToCsvTest {
@Mock
DocumentBuilderFactory factory;

@Mock
StreamSource style source;

@Mock
TransformerFactory transformerFactory;

@InjectMocks
XmlToCsv sut; // System Under Test

@Test
public void testOk() throws Exception {
// Mocks
DocumentBuilder documentBuilder = Mockito.mock(DocumentBuilder.class);
Document document = Mockito.mock(Document.class);
// Now you control all objects created in the class and you can test if the right methods are called

// when-clauses
Mockito.when(factory.newDocumentBuilder).thenReturn(documentBuilder);
Mockito.when(documentBuilder.parse(any(File.class)).thenReturn(document);
// Add all when's here

// now call the class
sut.xmlToCsv("", "", "");

// now verify all calls
verify(factory, times(1)).newDocumentBuilder();
verify(documentBuilder, times(1)).parse(any(File.class));
// etc.
}
}

The dirty way is using PowerMockito. With PowerMockito you can override the new methods of existing classes. It is really a last resort and I wouldn't recommend it, but you can use it when you can't change the source code. It will look something like this:

@RunWith(PowerMockRunner.class)
@PrepareForTest({XmlToCsv.class, DocumentBuilderFactory.class})
public class XmlToCsvTest {

XmlToCsv sut;

@Test
public void testXmlToCsv() throws Exception {
DocumentBuilder documentBuilder = Mockito.mock(DocumentBuilder.class);
Document document = Mockito.mock(Document.class);

//when phase
PowerMockito.mockStatic(DocumentBuilderFactory.newInstance).thenReturn(documentBuilder);
Mockito.when(factory.newDocumentBuilder).thenReturn(documentBuilder);
Mockito.when(documentBuilder.parse(any(File.class)).thenReturn(document);

// now call the class
sut.xmlToCsv("", "", "");

//now verify

verify(documentBuilder, times(1)).parse(any(File.class));
}
}

As you see the examples aren't complete, but you get the difference.

How to test a void method using Mockito

What exactly are you trying to test? Is that test that "when setImageOnImageView(RequestCreator, ImageView) is called, it invokes RequestCreator.into(ImageView)"?

If that's what you're trying to test, you aren't wanting to test that it "returns void". Rather, I would recommend something like:

@Test
public void itInvokesRequestCreatorIntoOnProvidedImageView() {
RequestCreator creator = mock(RequestCreator.class);
ImageView imageView = mock(ImageView.class);

setImageOnImageView(creator, imageView);
verify(creator).into(imageView);
}

In Java, How to test void method in Junit Mockito with assertion?

You need to capture the value passed to the dao save method. Use mockito's ArgumentCaptor for that. Then assert on that value.
Something along these lines:

ArgumentCaptor<Detail> captor = ArgumentCaptor.forClass(Detail.class);
verify(dyDBDAO, times(2)).save(captor.capture());
Detail detail1 = captor.getValues().get(0)
assertEquals(expectedDetail, detail1)

How to unit test a method which calls a void method?

You use the verify method:

verify(myRemovalService).removeData("Test1"));
verify(myRemovalService).removeData("Test2"));

Mockito to test void methods

Testing your code is not trivial, though not impossible. My first idea was to use ArgumentCaptor, which is much easier both to use and comprehend compared to ArgumentMatcher. Unfortunately the test still fails - reasons are certainly beyond the scope of this answer, but I may help if that interests you. Still I find this test case interesting enough to be shown (not correct solution):

@RunWith(MockitoJUnitRunner.class)
public class MessageServiceTest {

@Mock
private MessageDAO messageDAO = mock(MessageDAO.class);

private MessageService messageService = new MessageService();

@Before
public void setup() {
messageService.setDao(messageDAO);
}

@Test
public void testAcceptFromOffice() throws Exception {
//given
final Message message = new Message();

//when
messageService.acceptFromOffice(message);

//then
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);

verify(messageDAO, times(2)).makePersistent(captor.capture());

final List<Message> params = captor.getAllValues();
assertThat(params).containsExactly(message, message);

assertThat(params.get(0).getStatus()).isEqualTo(0);
assertThat(params.get(1).getStatus()).isEqualTo(1);
}

}

Unfortunately the working solution requires somewhat complicated use of Answer. In a nutshell, instead of letting Mockito to record and verify each invocation, you are providing sort of callback method that is executed every time your test code executes given mock. In this callback method (MakePersistentCallback object in our example) you have access both to parameters and you can alter return value. This is a heavy cannon and you should use it with care:

    @Test
public void testAcceptFromOffice2() throws Exception {
//given
final Message message = new Message();
doAnswer(new MakePersistentCallback()).when(messageDAO).makePersistent(message);

//when
messageService.acceptFromOffice(message);

//then
verify(messageDAO, times(2)).makePersistent(message);
}


private static class MakePersistentCallback implements Answer {

private int[] expectedStatuses = {0, 1};
private int invocationNo;

@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
final Message actual = (Message)invocation.getArguments()[0];
assertThat(actual.getStatus()).isEqualTo(expectedStatuses[invocationNo++]);
return null;
}
}

The example is not complete, but now the test succeeds and, more importantly, fails when you change almost anything in CUT. As you can see MakePersistentCallback.answer method is called every time mocked messageService.acceptFromOffice(message) is called. Inside naswer you can perform all the verifications you want.

NB: Use with caution, maintaining such tests can be troublesome to say the least.

Mocking a void method in the same class that is under test with mockito and junit5?

Do nothing works for me. Just pay attention to the calling order

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;

doNothing().when(yourMock).yourMethod(yourArgs);

This thread treats a similar problem, using a spy to mock specific methods with static factories should work. I've seen people doing to reverse operation (Use a Mock and then call the real method in some specific cases), but never tried it personally..



Related Topics



Leave a reply



Submit