Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock a void return method affecting an object

Tags:

I am writing unit tests for my application and I was wondering if it is possible for the Mockito framework to affect an object that is passed into a method that returns void of a mocked class. For instance, calling a mocked validation class that contains a method that returns void but tracks various changes and metadata via an object passed in as an argument. .

public GetCartItemsOutput getCartItems(GetCartItemsInput getCartItemsInput) {
    CartItemsFilter cartItemsFilter = new CartItemsFilter();
    validator.validateCartItemsInput(getCartItemsInput, cartItemsFilter); ...

I mocked the validator class for my other tests but for this one I need mock the changes to the cartItemsFilter object which I do not know how to do.

like image 634
tamuren Avatar asked Sep 14 '12 17:09

tamuren


People also ask

How do you mock method which returns void?

Mockito provides following methods that can be used to mock void methods. doAnswer() : We can use this to perform some operations when a mocked object method is called that is returning void. doThrow() : We can use doThrow() when we want to stub a void method that throws exception.

How do you unit test a void method without arguments?

Your modified program can ask for user input, call the function, then print the output. A testing framework can supply the input from a list of inputs to test, and check the outputs against the expected values. To test as-is, you'd have to intercept the input and output streams.

Does a void method return anything?

Void functions are created and used just like value-returning functions except they do not return a value after the function executes. In lieu of a data type, void functions use the keyword "void." A void function performs a task, and then control returns back to the caller--but, it does not return a value.

Can we mock a method in Junit?

While doing unit testing using junit you will come across places where you want to mock classes. Mocking is done when you invoke methods of a class that has external communication like database calls or rest calls.


2 Answers

The answer is yes, you can, and there are basically two levels of doing this, based on the need of your test.

If you merely want to test the interaction with the mocked object, you can simply use the verify() method, to verify that the void method was called.

If your test genuinely needs the mocked object to modify parameters passed to it, you will need to implement an Answer:

EDITED to show proper form of using Answer with void method

doAnswer(new Answer() {
    @Override
    Object answer(InvocationOnMock invocation) {
        Object[] args = invocation.getArguments();
        ((MyClass)args[0]).myClassSetMyField(NEW_VALUE);
        return null; // void method, so return null
    }
}).when(mock).someMethod();

In Java 8+, the above is simplified with a lambda:

doAnswer(invocation-> {
    Object[] args = invocation.getArguments();
    ((MyClass)args[0]).myClassSetMyField(NEW_VALUE);
    return null;
}).when(mock).someMethod();
like image 131
Kevin Welker Avatar answered Sep 19 '22 12:09

Kevin Welker


To add to Kevin Welker's answer, if your MyClass is a custom class, then define a equals/hashcode method in it, so that Mockito can use it to match to the method call exactly.

In my case, "MyClass" was in a third-party API, so I had to use the method "any" as below -

 doAnswer(new Answer() {
    Object answer(InvocationOnMock invocation) {
        Object[] args = invocation.getArguments();
        ((MyClass)args[0]).myClassSetMyField(NEW_VALUE);
        return null; // void method, so return null
    }
}).when(mock).someMethod(any(MyClass.class));
like image 42
Jay Khatwani Avatar answered Sep 16 '22 12:09

Jay Khatwani