John Lippson
John Lippson

Reputation: 1319

Unit Testing in Mockito, Calling a chain of functions on an object?

I've not done much testing and very minimal in Mockito. When I call delete on a certain object, I get a DeleteResponse. This has a method called getProcessingErrors() which is a set. I can then call .isEmpty() to see if there are errors or not. I'm trying to mock this out.

DeleteResponse deleteResponse = mock(DeleteResponse.class);

when(catalogFramework.delete(any(DeleteRequest.class))).thenReturn(deleteResponse);

when(deleteResponse.getProcessingErrors()).thenReturn(new HashSet<ProcessingDetails>());

PowerMockito.when(deleteResponse.getProcessingErrors().isEmpty()).thenReturn(true);

Error:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: 
Boolean cannot be returned by getProcessingErrors()
getProcessingErrors() should return Set
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
   Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies - 
   - with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.

Now, from the way I am reading this, it is saying isEmpty cannot return a boolean, but I believe it's cutting out early and just looking at the getProcessingErrors. How can I fix this?

Upvotes: 0

Views: 602

Answers (3)

Matthieu Grieger
Matthieu Grieger

Reputation: 160

You should be able to use Mockito's RETURNS_DEEP_STUBS to eliminate the need to mock the intermediate object:

DeleteResponse deleteResponse = mock(DeleteResponse.class, RETURNS_DEEP_STUBS);

when(catalogFramework.delete(any(DeleteRequest.class))).thenReturn(deleteResponse);

when(deleteResponse.getProcessingErrors().isEmpty()).thenReturn(true);

Although in this case, using RETURNS_DEEP_STUBS isn't really necessary... you can just initialize an empty HashSet and return it as follows:

when(deleteResponse.getProcessingErrors()).thenReturn(new HashSet<>());

This HashSet is empty, so it will return your desired result of true when calling isEmpty().

Upvotes: 0

Yogesh Badke
Yogesh Badke

Reputation: 4587

In here

when(deleteResponse.getProcessingErrors()).thenReturn(new HashSet<ProcessingDetails>());

PowerMockito.when(deleteResponse.getProcessingErrors().isEmpty()).thenReturn(true);

Either return Set with at least 1 element so that it returns true and you don't need the second line or Mock the HashSet also to return true when isEmpty() is called.

Without HashSet mocking

Set<ProcessingDetails> set = new HashSet<>();
set.add(new ProcessingDetails());
when(deleteResponse.getProcessingErrors()).thenReturn(set);

With HashSet mocking

HashSet<ProcessingDetails> mockedSet = mock(HashSet.class);
when(mockedSet.isEmpty()).thenReturn(true);
when(deleteResponse.getProcessingErrors()).thenReturn(set);

Upvotes: 1

Duong Anh
Duong Anh

Reputation: 557

You need mock deleteResponse.getProcessingErrors() object before mock isEmpty() function

when(deleteResponse.getProcessingErrors()).thenReturn(mockObject);
PowerMockito.when(mockObject.isEmpty()).thenReturn(true);

Upvotes: 3

Related Questions