Can we mock a spy object using mockito? - java

I have a class called RadiationControl and I created a spy for it in the following way.
RadiationControl radCtrl = new RadiationControl();
RadiationControl spyRadCtrl = Mockito.spy(radCtrl);
I have a chained method call inside a different class called StationMonitor which is being called by using the RadiationControl object. When I am trying to use the above created spy and trying to access that which has method parameters and they vary from time to time.
StationMonitorObject stationMonitorObject = radCtrl.getStationMonitorLoader().retrieveCVStationMonitorObject(Long.parseLong(syngId), status);
Thus with the above syntax when I try to stub the spy for that method call it's complaining to stub properly.
StationMonitorLoader stationMonitorLoader = StationMonitorLoader.getLoader(domain);
Mockito.doReturn(stationMonitorLoader).when(spyRadCtrl).getStationMonitorLoader();
Mockito.doReturn(stationMonitorObject).when(stationMonitorLoader).retrieveCVStationMonitorObject(any(Long.class), null);
Is there any better approach to deal such scenario ?

Is there any better approach to deal such scenario ?
Yes.
The problem here is:
radCtrl.getStationMonitorLoader()
.retrieveCVStationMonitorObject(Long.parseLong(syngId), status);
This is a violation of the law of demeter (aka don't talk to strangers!).
The method retrieveCVStationMonitorObject() should be available in class RadiationControl and delegate the call to its dependency (which looks like being a StationMonitorLoader...)

Related

Spying on instance variable and return the value when instance function get calls

I am trying to mock class instance and then return the mock object when we call the instance function but in result, it makes an actual call to function.
Here is my code:
AuthenticationSessionModel authSessionCookie =
new AuthenticationSessionManager(session)
.getCurrentAuthenticationSession(realm, client, tabId);
and my test code is:
AuthenticationSessionManager spyAuthSessionManager =
Mockito.spy(new AuthenticationSessionManager(session));
doReturn(authenticationSessionModel)
.when(spyAuthSessionManager)
.getCurrentAuthenticationSession(any(), any(), anyString());
It makes an actual call to getCurrentAuthenticationSession() and returns me Null Pointer Exception
In the test, you create a spy, and stub some behaviour.
But you don't use that spy in the code under test.
Instead, in the code under test you create a new AuthenticationSessionManager.
You need to restructure your code and:
create AuthenticationSessionManager outside of object under test.
pass it to object under test. Constructor is the first thing that comes to mind.
With these changes, it becomes trivial to substitute a real AuthenticationSessionManager with a spy in a test.

Writing testable code when new object is being constructed using Mockito only

So I am writing a class which I want to follow the best practices and be testable.
I have a new object to be created inside it. So, I am following the factory pattern to achieve it.
public class Apple {
// factory object injected in class
private SeedFactory seedFactory;
// Method to be tested
public void myMethod(String property1, int property2, String depends) {
// Just to set the necessary parameter
seedFactory = new SeedFactory(property1, property2);
// Factory pattern intact. Instance generation depends on only one parameter
SeedFactory result = seedFactory.getInstance(depends);
}
}
EDIT: Adding code for factory as well.
public class SeedFactory{
String property1;
int property2;
SeedFactory(property1,property2){
this.property1 = property1;
this.property2 = property2;
}
SeedFactory getInstance(int depends){
if(depends == 1)
{ // do stuff }
else{ // do stuff and return instance }
Now, before I actually create the new object, I have to make sure that I set two properties for the new instance to be generated, which are needed to be present irrespective of the type of instance generated by the factory. depends is the actual parameter which tells the factory what instance to return.
Now, as far as testability of this code is concerned, I can user PowerMockito to mock the factory object using whenNew but using PowerMockito is not a choice. I have to make it testable without it.
Also, I have tried to encapsulate the new call within a one line function and then use spy. But I want to avoid using spy, since it is not considered a good practice, in context of where this code is being used as a whole.
So my question is, Is there any way, without using PowerMockito, to re-write this class so that it can be unit tested properly?
If the instance to be generated needed only one parameter, then it would have been trivial. However, I don't want to pass more than one parameter to getInstance().
SeedFactory is not Apple's dependancy but your method depends on SeedFactory which has "uses" relationship. So to define proper relation i would suggest you use "USES" relation as below:
public void myMethod(SeedFactory seedFactory, String depends){ // Method to be tested
Now you could mock SeedFactory and can unit test it appropriately.
I think you're doing something wrong.
If SeedFactory isn't an Apple's dependency but an internal concern, hence you don't need to mock a SeedFactory to test Apple. You should test the public API provided by Apple only.
If SeedFactory is an Apple's dependency, so it definitely should be injected.

mockito - how to check an instance inside a method

I am new to Mockito, I am trying to verify the attributes of an object which gets created inside a method.
pseudo code below:
class A{
...
public String methodToTest(){
Parameter params = new Parameter(); //param is basically like a hashmap
params.add("action", "submit");
return process(params);
}
...
public String process(Parameter params){
//do some work based on params
return "done";
}
}
I want to test 2 things:
when I called methodToTest, process() method is called
process() method is called with the correct params containing action "submit"
I was able to verify that process() is eventually called easily using Mockito.verify().
However trying to check that params contains action "submit" is very difficult so far.
I have tried the following but it doesn't work :(
BaseMatcher<Parameter> paramIsCorrect = new BaseMatcher<Parameter>(){
#Overrides
public boolean matches(Object param){
return ("submit".equals((Parameter)param.get("action")));
}
//#Overrides description but do nothing
}
A mockA = mock(A);
A realA = new A();
realA.methodToTest();
verify(mockA).process(argThat(paramIsCorrect))
Any suggestion ?
If you have got verify() to work, presumably it is just a case of using an argument matcher to check the contains of params.
http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#3
The example given in the above docs is verify(mockedList).get(anyInt()). You can also say verify(mockedList).get(argThat(myCustomMatcher)).
As an aside, it sounds like you are mocking the class under test. I've found that this usually means I haven't thought clearly about either my class or my test or both. In your example, you should be able to test that methodToTest() returns the right result irrespective of whether or not it calls process() because it returns a String. The mockito folk have lots of good documentation about this sort thing, particularly the "monkey island" blog: http://monkeyisland.pl/.
Just pass Parameter in as a constructor argument to a constructor of the class A, then use a mocked instance/implementation of Parameter in your test and verify on the mock. That is how it is normally done - you separate your classes and compose them using constructor injection, that enables you to pass in mocks for testing purposes (it also allows rewiring the application and exchanging some commons a lot easier).
If you need to create Parameter on every function invocation you should use a factory that creates Parameter instances and pass that in. Then you can verify on the factory as well as the object created by the factory.

Changing fields of a mockito spy

So lets say I have a class
class JustAClass() {
Stirng justAField = "nothing";
}
Now I'm testing this class and I put it into a mock
JustAClass realClass = newJustACLass();
JustAClass spyClass = Mockito.spy(realClass);
spyClass.justAField = "something"
Question is: What does the realClass.justAField equal now?
EDIT: In response to #fge
This didn't fail.
CSVExport spyClass = Mockito.spy(testClass);
FileOutputStream wFile = Mockito.mock(FileOutputStream.class);
spyClass.wFile = wFile;
Mockito.doThrow(IOException.class).when(spyClass).createBlankWorkbook();
spyClass.export(testEnabledFields);
Mockito.doThrow(IOException.class).when(wFile).close();
spyClass.export(testEnabledFields);
So is the wFile in testClass the mock now, or the original?
Pulling this from api doc http://docs.mockito.googlecode.com/hg-history/be6d53f62790ac7c9cf07c32485343ce94e1b563/1.9.5/org/mockito/Spy.html
Mockito does not delegate calls to the passed real instance, instead it actually creates a copy of it. So if you keep the real instance and interact with it, don't expect the spied to be aware of those interaction and their effect on real instance state. The corollary is that when an unstubbed method is called on the spy but not on the real instance, you won't see any effects on the real instance

Spring AOP advice is not getting called

My advice is not getting called for method getPOInvoice method from this method, but if I call it separately then advice is getting called and getPOInvoice and getPOInvoice is declared in same class.
public StreamingOutput getPDFStream(String invoiceId, String versionNumber) throws TugnavException {
final POInvoice poInv = getPOInvoice(invoiceId, versionNumber);
...
}
My advice is:
#AfterReturning(value="execution(* com.tugnav.service.facade.*.get*(..))", returning="doc")
public TugnavBaseDocument setupTimeCreatedString(TugnavBaseDocument doc){
...
}
If I call this method from another class then advice is getting called.
Why is it not getting called internally?
You need to read the documentation about proxies here.
Basically, because of the way proxies are generated, a instance method call within another instance method will not trigger an aspect (or proxy behavior).
Given:
class FooBar {
// advised method
public void foo() {
bar();
}
// would've been advised
public void bar() {
// ... do something
}
}
Say an instance of FooBar was proxied, a call to foo() will trigger the aspect because from outside you have a reference to the proxy object. When you call bar() internally, you have access to this (equivalent to this.bar()) which is a reference to the target instance, the actual object, so there is no added behavior.
There are a few ways to solve this problem, but probably not the way you want. See the answer to this question.
AOP would not normally work this way.
AOP is added as an aspect through Proxies, to compiled class, so it does not have any effect on the internal class invocations.
When it's an outer cal, you are actually referring to some Proxy which intercepts your call and triggers appropriate AOP calls.
When it's internal cal, inside the class, it is a direct call, without any Proxy involved.
As a solution you can do following:
Refactore service you are using, to exclude internal calls
Alter bytecode on Class loading, with your AOP functionality :)
If you want that your advice is called for getPOInvoice method when you are invoking from method getPDFStream(..), both in the same bean, you can't use a proxy-based AOP, like Spring use by default. Instead you should use load time weaving(LTW) with AspectJ.
http://static.springsource.org/spring/docs/3.2.2.RELEASE/spring-framework-reference/html/aop.html#aop-aj-ltw

Categories