I'm trying to spy a Java class in a Spock test. I've not had a problem with Mockito in Spock/Groovy before.
When I try to do the following:
def service = spy(Service.class)
I get the following error:
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class java.lang.Class
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
When I do mock(Service.class) though, it works fine.
I have confirmed that the class is not final, anonymous, or primitive.
Any ideas? I have a random generator in the class (ak) so I need to spy not mock.
Thank you
Mockito doesn't spy on Classes (or Mocks), it spies on (regular) Objects. Thus, instead of
def service = spy(Service.class)
you have to write
def service = spy(new Service())
(or whichever constructor is appropriate for your scenario).
Just an extra to Ray's answer, you can also spy on already created instances. The only thing is that all methods you called before spy() was called, cannot be verified. Like:
ClassToSpy spiedInstance;
#Before
public void before () {
spiedInstance = new ClassToSpy();
}
#Test
public void testWillFail() {
spiedInstance.method();
spiedInstance = spy(spiedInstance);
verify(spiedInstance).method();
}
#Test
public void testWillPass() {
spiedInstance = spy(spiedInstance);
spiedInstance.method();
verify(spiedInstance).method();
}
The error you would get from testWillFail would be similar to:
Wanted but not invoked:
classToSpy.method();
-> at your.package.testWillFail(TestClass.java:line)
Actually, there were zero interactions with this mock.
Due to the fact that, after spied, you did not call this method.
Related
I need mock some class with final method using mockito. I have wrote something like this
#Test
public void test() {
B b = mock(B.class);
doReturn("bar called").when(b).bar();
assertEquals("must be \"overrided\"", "bar called", b.bar());
//bla-bla
}
class B {
public final String bar() {
return "fail";
}
}
But it fails.
I tried some "hack" and it works.
#Test
public void hackTest() {
class NewB extends B {
public String barForTest() {
return bar();
}
}
NewB b = mock(NewB.class);
doReturn("bar called").when(b).barForTest();
assertEquals("must be \"overrided\"", "bar called", b.barForTest());
}
It works, but "smells".
So, Where is the right way?
Thanks.
From the Mockito FAQ:
What are the limitations of Mockito
Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.
There is no support for mocking final methods in Mockito.
As Jon Skeet commented you should be looking for a way to avoid the dependency on the final method. That said, there are some ways out through bytecode manipulation (e.g. with PowerMock)
A comparison between Mockito and PowerMock will explain things in detail.
You can use Powermock together with Mockito, then you do not need to subclass B.class. Just add this to the top of your test class
#RunWith(PowerMockRunner.class)
#PrepareForTest(B.class)
#PrepareForTest instructs Powermock to instrument B.class to make the final and static methods mockable. A disadvantage of this approach is that you must use PowerMockRunner which precludes use of other test runners such as the Spring test runner.
Mockito 2 now supports mocking final methods but that's an "incubating" feature. It requires some steps to activate it which are described here:
https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
Mockito 2.x now supports final method and final class stubbing.
From the docs:
Mocking of final classes and methods is an incubating, opt-in feature. This feature has to be explicitly activated by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
After you create this file you can do:
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios.
Assuming that B class is as below:
class B {
private String barValue;
public final String bar() {
return barValue;
}
public void final setBar(String barValue) {
this.barValue = barValue;
}
}
There is a better way to do this without using PowerMockito framework.
You can create a SPY for your class and can mock your final method.
Below is the way to do it:
#Test
public void test() {
B b = new B();
b.setBar("bar called") //This should the expected output:final_method_bar()
B spyB = Mockito.spy(b);
assertEquals("bar called", spyB.bar());
}
Mockito can be used to mock final classes or final methods. The problem is, this doesn't come as out of the box feature from Mockito and needs to be configured explicitely.
So, in order to do that,
Create a text file named org.mockito.plugins.MockMaker to the project's src/test/resources/mockito-extensions directory and add a single line of text as below
mock-maker-inline
Once done, you can use the mockito's when method to mock the behaviour like any other regular method.
See detailed examples here
I just did this same thing. My case was that I wanted to ensure the method didn't cause an error. But, since it's a catch/log/return method, I couldn't test for it directly without modifying the class.
I wanted to simply mock the logger I passed in. But, something about mocking the Log interface didn't seem to work, and mocking a class like SimpleLog didn't work because those methods are final.
I ended up creating an anonymous inner class extending SimpleLog that overrode the base-level log(level, string, error) method that the others all delegate to. Then the test is just waiting for a call with a level of 5.
In general, extending a class for behavior isn't really a bad idea, and might be preferable to mocking anyway if it's not too complicated.
I have a unit test that fails because it indirectly calls a method which is dependent upon a service. But when unit tests are run, the service is offline. I tried using Mockito for mocking the behavior of this service dependent method, but the problem is that this method is a static method in a final class, so Mockito does not work in this case.
I also tried using PowerMock with Mockito, but again as the method is not called directly from the unit test, it does not work. This is the skeleton of my unit test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(FinalClassWithStaticMethod.class)
public class MyObjTestCase {
#Test public void myRandomTest() throws Exception {
PowerMockito.mockStatic(FinalClassWithStaticMethod.class);
MyObj returnObj = new MyObj();
// setup fields for returnObj
...
...
PowerMockito.when(FinalClassWithStaticMethod.staticMethod((AnotherObj)anyObject())).thenReturn(returnObj);
AnotherObj obj = new AnotherObj();
// setup fields for obj...
MyObj mockedObj = FinalClassWithStaticMethod.staticMethod(obj); // This returns the mocked value.
// TestUtil.staticMethod calls another class' method which calls FinalClassWithStaticMethod.staticMethod.
MyObj myObj = TestUtil.staticMethod(obj); // This does not return mocked value.
}
}
My questions:
Are the unit tests even meant for such scenarios?
Is there a way by which I can get this unit test to work without modifying the final class? In case I do have to modify the existing classes, what is the correct way of doing it by minimal effects on the dependent code? Although it is a specific scenario, links to examples that exhibit such refactoring will be great help.
In your case, you should ideally be mocking the service object. The mocking will only work if the method that is calling the service is using the mocked object. If the client for the service can be created and passed to the class calling the service directly from the unit test (setter/constructor) when the object is created in the unit test, then you don't have to make too many changes.
Sample code:
class CallsService {
public CallsService(final ServiceClient client) {
... }
public someMethod() {
client.callService();
}
}
In unit test:
void test() {
ServiceClient mockedClient = mock(ServiceClient.class);
// Setup mocks to return as required
CallsService caller = new CallsService(mockedClient);
}
This way the caller will use the mockedClient in the unit test, and in the actual program it can get a client to the real service.
Trying to broaden the appeal of Spock at work and run into this issue. Actually trying to write Unit Tests for a Groovy class, but one that calls out to Java. A static method calls a private constructor. The code looks like:
private MyConfigurator(String zkConnectionString){
solrZkClient = new SolrZkClient(zkConnectionString, 30000, 30000,
new OnReconnect() {
#Override
public void command() { . . . }
});
}
"SolrZkClient" is from third party (Apache) Java library. Since it tries to connect to ZooKeeper, I would like to mock that out for this Unit Test (rather than running one internally as part of the unit test).
My test gets to the constructor without difficulty, but I can't get past that ctor:
def 'my test'() {
when:
MyConfigurator.staticMethodName('hostName:2181')
then:
// assertions
}
Is there anyway to do this?
Since the class under test is written in Groovy, you should be able to mock the constructor call by way of a global Groovy Mock/Stub/Spy (see Mocking Constructors in the Spock Reference Documentation). However, a better solution is to decouple the implementation of the MyConfigurator class, in order to make it more testable. For example, you could add a second constructor and/or static method that allows to pass an instance of SolrZkClient (or a base interface, if there is one). Then you can easily pass in a mock.
You can use GroovySpy for mocking constructors in Spock
For example:
def 'my test'() {
given:
def solrZkClient = GroovySpy(SolrZkClient.class,global: true);
when:
MyConfigurator.staticMethodName('hostName:2181')
then:
// assertions
}
def anySubscriber = GroovySpy(RealSubscriber, global: true)
1 * new RealSubscriber("Fred")
put that into def setup(){ } block or inside of given: label block
I am using Mockito to test my classes. I am trying to use Deep stubbing as I didn't a way on injecting a Mock inside another mock object in Mockito.
class MyService{
#Resource
SomeHelper somehelper;
public void create()
{
//....
somehelper.invokeMeth(t);
}
}
class SomeHelper{
#Resource
private WebServiceTemplate webServiceTemplate;
public void invokeMeth(T t)
{
try{
//...
webServiceTemplate.marshalSendAndReceive(t);
}catch (final WebServiceIOException e) {
throw new MyAppException("Service not running");
}
}
}
Now I am trying to Unit test the MyService class's create() method.
I have injected a mock for SomeHelper as follows
#Mock(answer = Answers.RETURNS_DEEP_STUBS)
SomeHelper somehelper;
What I want now is when the invokeMeth() method gets called on the mocked somehelper object it calls the real method in this case.
when(somehelper.invokeMeth(isA(RequestObject.class)))
.thenCallRealMethod();
I was expecting the webServiceTemplate not be null in this case.
However I get a Nullpointer exception when the code tries to execute the line
webServiceTemplate.marshalSendAndReceive(t);
Any clue how I can get access to a deep mock object (i.e. mock within a mock - in this case webserviceTemplete mock inside somehelper mock) and then apply a when condition to throw a WebserviceIOException ?
I want this so that I can test the MyService.create() to check it behaves properly when a WebServiceIOException is thrown down the code.
Yes of course, you are mixing real objects and mocks. Plus using the thenCallRealMethod lloks like a partial mock, it feels wrong here, it's no wonder the javadoc of this method talks about that as well.
I definatelty should stress you than, design wise, having a mock that returns a mock is often a smell. More precisely you are breaking the Demeter Law, or not following the Tell, Don't Ask principle.
Any looking at your code I don't why the code would need to mock WebServiceTemplate. You want to unit test MyService, and I don't see a relationship to WebServiceTemplate. Instead you should focus on the interactions with you helper only. And unit test SomeHelper separately where you'll be able to check the interactions between SomeHelper and WebServiceTemplate.
Here's a little example of how I see the thing:
public void ensure_helper_is_used_to_invoke_a_RequestObject() {
// given a service that has an helper collaborator
... other fixture if necessary
// when
myService.behaviorToTest();
// then
verify(someHelperMock).invokeMeth(isA(RequestObject.class));
}
How those that look for your real use case ?
Hope that helps
I need mock some class with final method using mockito. I have wrote something like this
#Test
public void test() {
B b = mock(B.class);
doReturn("bar called").when(b).bar();
assertEquals("must be \"overrided\"", "bar called", b.bar());
//bla-bla
}
class B {
public final String bar() {
return "fail";
}
}
But it fails.
I tried some "hack" and it works.
#Test
public void hackTest() {
class NewB extends B {
public String barForTest() {
return bar();
}
}
NewB b = mock(NewB.class);
doReturn("bar called").when(b).barForTest();
assertEquals("must be \"overrided\"", "bar called", b.barForTest());
}
It works, but "smells".
So, Where is the right way?
Thanks.
From the Mockito FAQ:
What are the limitations of Mockito
Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.
There is no support for mocking final methods in Mockito.
As Jon Skeet commented you should be looking for a way to avoid the dependency on the final method. That said, there are some ways out through bytecode manipulation (e.g. with PowerMock)
A comparison between Mockito and PowerMock will explain things in detail.
You can use Powermock together with Mockito, then you do not need to subclass B.class. Just add this to the top of your test class
#RunWith(PowerMockRunner.class)
#PrepareForTest(B.class)
#PrepareForTest instructs Powermock to instrument B.class to make the final and static methods mockable. A disadvantage of this approach is that you must use PowerMockRunner which precludes use of other test runners such as the Spring test runner.
Mockito 2 now supports mocking final methods but that's an "incubating" feature. It requires some steps to activate it which are described here:
https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
Mockito 2.x now supports final method and final class stubbing.
From the docs:
Mocking of final classes and methods is an incubating, opt-in feature. This feature has to be explicitly activated by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
After you create this file you can do:
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios.
Assuming that B class is as below:
class B {
private String barValue;
public final String bar() {
return barValue;
}
public void final setBar(String barValue) {
this.barValue = barValue;
}
}
There is a better way to do this without using PowerMockito framework.
You can create a SPY for your class and can mock your final method.
Below is the way to do it:
#Test
public void test() {
B b = new B();
b.setBar("bar called") //This should the expected output:final_method_bar()
B spyB = Mockito.spy(b);
assertEquals("bar called", spyB.bar());
}
Mockito can be used to mock final classes or final methods. The problem is, this doesn't come as out of the box feature from Mockito and needs to be configured explicitely.
So, in order to do that,
Create a text file named org.mockito.plugins.MockMaker to the project's src/test/resources/mockito-extensions directory and add a single line of text as below
mock-maker-inline
Once done, you can use the mockito's when method to mock the behaviour like any other regular method.
See detailed examples here
I just did this same thing. My case was that I wanted to ensure the method didn't cause an error. But, since it's a catch/log/return method, I couldn't test for it directly without modifying the class.
I wanted to simply mock the logger I passed in. But, something about mocking the Log interface didn't seem to work, and mocking a class like SimpleLog didn't work because those methods are final.
I ended up creating an anonymous inner class extending SimpleLog that overrode the base-level log(level, string, error) method that the others all delegate to. Then the test is just waiting for a call with a level of 5.
In general, extending a class for behavior isn't really a bad idea, and might be preferable to mocking anyway if it's not too complicated.