Mockito Inline Mock Maker - throws Exception - Argument passed to when() is not a mock - unit-testing

I wanted to mock static methods, hence used dependency "mockito-inline" 3.8 version instead of "mockito-core"
The static method mocks work fine but my old tests that mock interfaces fail with the below error
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!
Example of correct stubbing:
doThrow(new RuntimeException()).when(mock).someMethod();
Reverting to using mockito-core solves the issue but then I would not be able to mock static methods
Is there any way we can choose different mockito engines (Subclass/Inline) for each class?

MockResolver fixed the issue as described in https://github.com/mockito/mockito/issues/1980

If you need to mock static methods and you cannot use mockito-inline you could do something like this with mockito-core:
public class MockitoUtil {
public static <T, S> void mockStaticMethod(Class<T> classToMock, String nameOfMethodToMock, S result) {
MockCreationSettings<T> settings = mock(MockCreationSettings.class);
when(settings.isSerializable()).thenReturn(true);
MockHandler<T> handler = new MockHandler<>() {
private static final long serialVersionUID = 1L;
#Override
public Object handle(Invocation invocation) throws Throwable {
String invokedMethodName = invocation.getMethod().getName();
if(!invokedMethodName.equals(nameOfMethodToMock)){
String message = "called %s on class %s, but only %s was implemented";
throw new Exception(String.format(message, invokedMethodName, classToMock.getName(), nameOfMethodToMock));
}
return result;
}
#Override
public MockCreationSettings<T> getMockSettings() { return null; }
#Override
public InvocationContainer getInvocationContainer() { return null; }
};
MockMaker.StaticMockControl<T> classToMockControl = Mockito
.framework()
.getPlugins()
.getInlineMockMaker()
.createStaticMock(classToMock, settings, handler);
classToMockControl.enable();
}
}
N.B. you should call classToMockControl.disable() after the static method invocation if you'd like to mock static methods of other classes in the same test

Related

How to mock customized logger with static keyword using Mockito?

I have created customized logging library named "StandardLogger" in which I am using logback for logging. Now I want to mock it in unit test but I am unable to do it.
Function I want to mock is static
public static String getHostOrDefault(String url, String defaultHost) {
try {
return new URL(url).getHost();
} catch (MalformedURLException e) {
logger.error("ConfigurationProvider", "getHostOrDefault", "Exception returning default host : "+ defaultHost + " Exception : "+e);
}
return defaultHost;
}
Class name and field
#Context
public class ConfigurationProvider {
private static final StandardLogger logger = new StandardLogger("CATS");
My Test class with unit test
class ConfigurationProviderTest {
#InjectMocks
ConfigurationProvider configurationProvider;
#Mock
private StandardLogger logger= new StandardLogger("CATS");
#Test
void thatGetHostOrDefaultReturnsHost() {
Mockito.doNothing().when(logger).info(Mockito.anyString(),Mockito.anyString(),Mockito.anyString());
String hostOrDefault = ConfigurationProvider.getHostOrDefault("http://abc.host:9433", "host");
assertThat(hostOrDefault, is("abc.host"));
}
Now when I am running it in debug mode logger object is NULL .
First of all, in the class under test you aren't injecting the logger. This means that you cannot inject it from the junit either. And exactly this happens: your logger is null in your class under test!
The second problem faces to you is about static methods. I've never been able to mock static method without using PowerMockito, even if here there is an interesting article that says that you can do it.

Mockito method call stub not working - Mockito.doReturn(false).when(studentServiceImpl).myClass().isValidUser(ArgumentMatchers.anyInt());

adding test cases for getStudent method, this is having internal calls
1- is repository call - stubbing this call working fine
2- validate user call - stubbing this call not working, showing some error and test case failed.
Service Class
#Service
public class StudentServiceImpl implements StudentService {
#Autowired
FakeStudentRepository fakeStudentRepository;
#Override
public Optional<Student> getStudent(int id) {
Optional<Student> student = fakeStudentRepository.getStudent(id);
boolean isValid = myClass().isValidUser(student.get().getId());
if(!isValid) {
return Optional.empty();
}
return student;
}
public MyTestClass myClass() {
return new MyTestClass();
}
}
MyTestClass
public class MyTestClass {
public boolean isValidUser(int id) {
return true;
}
}
Test Class
#SpringBootTest
class StudentServiceImplTest {
#Mock
FakeStudentRepository fakeStudentRepository;
#InjectMocks
StudentServiceImpl studentServiceImpl;
#BeforeEach
public void setup() {
studentServiceImpl = Mockito.spy(StudentServiceImpl.class);
MockitoAnnotations.initMocks(this);
}
#Test
void getStudent() {
Optional<Student> student = Optional.of(Student.builder().id(1).firstName("Rahul").lastName("rahul")
.mobile("XXXXXX").build());
Mockito.doReturn(student)
.when(fakeStudentRepository).getStudent(ArgumentMatchers.anyInt());
Mockito.doReturn(false)
.when(studentServiceImpl).myClass().isValidUser(ArgumentMatchers.anyInt());
Optional<Student> resultStudent = studentServiceImpl.getStudent(student.get().getId());
assertEquals(resultStudent.get().getId(), student.get().getId());
}
}
Error
org.mockito.exceptions.misusing.WrongTypeOfReturnValue: Boolean
cannot be returned by myClass() myClass() should return MyTestClass
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.
The error Message says it: You are mocking studentServiceImpl.myClass() and try to return true. It’s not possible to mock the end of a call chain as you try with your second Mockito expression.
To do what you want requires to mock myClass() first by returning a mocked class instance and mock isValidUser on that.

How to mock a static method inside a factory class

I need to mock the behavior of a static method inside a non-static factory class. The implementation of the class is:
ABCFactory.java
public class ABCFactory extends BaseUserFactory
{
private static final ABCFactory factory = new ABCFactory();
public static final ABCFactory getFactory()
{
return factory;
}
public Context getContext(String authority)
{
return (Context)createInstance(authority);
}
private ABCFactory()
{
}
protected Class getInterface()
{
return ABCFactory.class;
}
}
Now, this class is used in my code to get the profile something like:
Document.java:
Profile profile = ABCFactory.getFactory().getContext(authority).currentProfile();
I need to mock the ABCFactory class so that I can send my own context/profile object as a return type while testing. I've tried a bunch of methods but nothing seems to work here. Here's what I tried in my junit test class.
Try 1:
DocumentTest.java
ABCFactory mockABCFactory = Mockito.mock(ABCFactory.class);
ServiceProviderRegistrar.getRegistrar().bind(ABCFactory.class).toMockInstance(mockABCFactory);
Mockito.when(mockABCFactory .getFactory()).thenReturn(null);
Mockito.when(mockABCFactory .getContext(domain)).thenReturn(null);
Error:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
2. inside when() you don't call method on mock but on some other object.
Try 2: (Using PowerMock to avoid the new call.
DocumentTest.java
ABCFactory mockABCFactory = Mockito.mock(ABCFactory.class);
ServiceProviderRegistrar.getRegistrar().bind(ABCFactory.class).toMockInstance(mockABCFactory);
try
{
PowerMockito.whenNew(ABCFactory.class).withNoArguments().thenReturn(mockABCFactory);
PowerMockito.when(ABCFactory.getFactory()).thenReturn(mockABCFactory);
}
catch (Exception e)
{
e.printStackTrace();
}
Mockito.when(mockABCFactory.getContext(domain)).thenReturn(null);
Error:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
2. inside when() you don't call method on mock but on some other object.
at org.powermock.api.mockito.PowerMockito.when(PowerMockito.java:490)
Try 3: (Used PowerMock.mockStatic)
DocumentTest.java
ABCFactory mockABCFactory= Mockito.mock(ABCFactory.class);
ServiceProviderRegistrar.getRegistrar().bind(ABCFactory.class).toMockInstance(mockABCFactory);
try
{
PowerMockito.whenNew(ABCFactory.class).withNoArguments().thenReturn(mockABCFactory);
PowerMockito.mockStatic(ABCFactory.class);
PowerMockito.when(ABCFactory.getFactory()).thenReturn(mockABCFactory);
}
catch (Exception e)
{
e.printStackTrace();
}
Mockito.when(mockABCFactory.getContext(domain)).thenReturn(null);
Error:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
2. inside when() you don't call method on mock but on some other object.
at org.powermock.api.mockito.PowerMockito.when(PowerMockito.java:490)
What am I missing here. I have tried several other ways but ABCFactory.getFactory() always returns a new object but not my mocked object. How do I mock the behavior of ABCFactory class without changing its implementation?! Please help.
Did you use following annotations.
#RunWith(PowerMockRunner.class)
#PrepareForTest( ABCFactory.class )
I tried and following code works.
DocumentTest.class
#RunWith(PowerMockRunner.class)
#PrepareForTest( ABCFactory.class )
public class DocumentTest
{
/** Unit under test. */
private Document user;
#Before public void setUp() {
user = new Document();
ABCFactory abc = ABCFactory.getFactory();
PowerMockito.mockStatic(ABCFactory.class);
PowerMockito.when(ABCFactory.getFactory()).thenReturn(abc);
}
#Test public void testABC() {
assertEquals("", user.useFactory() );
}
}
Document class
public class Document
{
public String useFactory(){
String profile = ABCFactory.getFactory().getContext("");
return profile;
}
}

How to verify some other object was constructed, when using mockito

I have following Java code that I want to test. What I am having difficulty is figuring out how do I verify that call to handleAppVersionRequest , actually constructs AppVersionResponse object. Is there any way to do that using Mockito?
Here code is code for method:
class MyClass {
public void handleAppVersionRequest(String dataStr,
final int dataChannelId) {
String ver = "1.0";
final AppVersionResponse resp = new AppVersionResponse(ver);
Timber.d("Sending data %s", resp.toString());
sendResponse(dataChannelId, getGson().toJson(resp));
}
}
And here is method for test:
#Test
public void testHandleAppVersionRequest() throws Exception {
MyClass presenter = Mockito.spy(new MyClass());
String versionRequestJson = "{\"command\":1}";
when(presenter.getGson()).thenReturn(gSon);
presenter.handleAppVersionRequest(versionRequestJson,0);
// How do I verify that AppResponse object was constructed?
verify(presenter,times(1)).sendResponse(anyInt(),anyString());
}
If you must test the creation of the object during a unit test, you can extract a factory, mock it for your test, and then verify that the create method is called on it.
At the same time, consider spending some time looking at some tutorials for Mockito and unit testing in general, like this one. You should choose one class that is going to be the 'system under test'. Don't spy or mock this class! Instead, pass in mocks as dependencies that you will use to test the behaviour of your class.
Here is a factory extracted from your MyClass:
class AppVersionResponseFactory {
AppVersionResponse create(String version) {
return new AppVersionResponse(version);
}
}
Then the refactored version of your class where the dependencies (Gson and the factory) are passed in through the constructor:
class MyClass {
//dependencies that can now be mocked!
private final AppVersionResponseFactory appVersionResponseFactory;
private final Gson gson;
//pass the mockable dependencies in the constructor of the system under test!
public MyClass(AppVersionResponseFactory appVersionResponseFactory, Gson gson) {
this.appVersionResposeFactory = factory;
this.gson = gson;
}
public void handleAppVersionRequest(String dataStr, final int dataChannelId) {
String ver = "1.0";
AppVersionResponse resp = AppVersionResponseFactory.create(ver);
Timber.d("Sending data %s", resp.toString());
sendResponse(dataChannelId, gson.toJson(resp));
}
}
Now your test looks something like this:
//mocks
AppVersionResponseFactory mockAppVersionResposeFactory;
Gson mockGson;
//system under test
MyClass myClass;
#Before
public void setUp() {
mockAppVersionResposeFactory = Mockito.mock(AppVersionResponseFactory.class);
mockGson = Mockito.mock(Gson.class);
myClass = new MyClass(mockGson, mockAppVersionResposeFactory);
}
#Test
public void testHandleAppVersionRequest() throws Exception {
String versionRequestJson = "{\"command\":1}";
myClass.handleAppVersionRequest(versionRequestJson, 0);
verify(appVersionResposeFactory).create("1.0");
}
Please note that although your question asks for a way to verify the construction of an object, a better test would probably test the final outcome of that method i.e., that sendResponse was called with the correct dataChannelId and correct JSON. You can use the same techniques in this answer to do that i.e., extracting a dependency (perhaps a ResponseSender?), passing it in the constructor for your MyClass, mocking it in the test, then calling verify on it.

How to use dynamic partial mocking with JMockit and Logger interface?

I've been working with JMockit and its admittedly steep learning curve. I'm pretty new with mocking in general so please excuse the ignorance.
I'm trying to mock out the Logger interface so that I can verify the catch statement is working correctly. Call this an exercise in understanding how JMockit works. The implementing class for the Logger interface is Log4jLoggerAdapter so I thought if I passed an instance of that into my Expectations() block, JMockit would use dynamic partial mocking and "see" my logger statement. Instead, I get the following error:
mockit.internal.MissingInvocation: Missing invocation of: org.slf4j.impl.Log4jLoggerAdapter#error(String msg, Throwable t)
The Class Being Tested
public class MyLoggedClass {
private static final Logger LOGGER = LoggerFactory.getLogger(MyLoggedClass.class);
... // Other variables
#Override
public void connect() {
String info = getServiceInfo();
try {
connector = MyConnectionFactory.connect(info);
} catch (Exception e) {
LOGGER.error("Exception connecting to your service with: " + info, e);
}
}
... // Other methods
}
My #Test
public class MyLoggedClassTest {
#Tested
MyLoggedClass myLoggedClass;
#Test
public void myLoggingTest(#Mocked final Log4jLoggerAdapter logger){
new Expectations(MyConnectionFactory.class, logger){{
MyConnectionFactory.connect(anyString);
result = new Exception();
logger.error(anyString, (Throwable)any);
}};
myLoggedClass.connect();
}
I'd detail the other approaches I've tried but this page would turn into a book. This is my best approach. Any ideas?
* Update * (yes, that was quick)
I changed #Mocked to #Cascading and removed the logger field from my Expectations signature and it worked. I don't understand why. Can someone please provide an explanation? Fumbling about until you stumble on something that works but you don't understand is not a recipe for success. See below:
#Test
public void myLoggingTest(#Cascading final Log4jLoggerAdapter logger){
new Expectations(MyConnectionFactory.class){{
MyConnectionFactory.connect(anyString);
result = new Exception();
logger.error(anyString, (Throwable)any);
}};
myLoggedClass.connect();
}
No need for partial mocking in this case, just mock MyConnectionFactory in the usual way. The only tricky part is how to mock the class that implements the Logger interface, considering that it's instantiated from a static class initializer. As it happens, there is a feature in the mocking API for that (using JMockit 1.14):
public class MyLoggedClassTest
{
#Tested MyLoggedClass myLoggedClass;
#Test
public void myLoggingTest(
#Mocked MyConnectionFactory conFac,
#Capturing final Logger logger)
{
new Expectations() {{
MyConnectionFactory.connect(anyString);
result = new Exception();
}};
myLoggedClass.connect();
new Verifications() {{
logger.error(anyString, (Throwable)any);
}};
}
}
With a #Capturing mocked type, any implementation class will get mocked, so the test doesn't need to know about Log4jLoggerAdapter.