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

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.

Related

Using PowerMockito and Mockito to test call to other artifact's method

I am sure this is quite a common question now, but I really can't get away with this issue I am having on mocking private method which internally calls another method and returns a collection.
Class that I am testing has a public method which calls private method to get Collection object. I use PowerMock to create a spy of private method.
public void method1(String s)
{
Collection<Object> list = invokePrivate()
}
private Collection<Object> invokePrivate()
{
Wrapper wrapperObj = Factory.getInstance.getWrapper();
Collection<Object> list = wrapperObj.callWrapperMethod(); // This always calls into real method, instead of mocked version.
return list;
}
Test Class-:
So In order to test public method "method1" I create a spy using PowerMockito to spy over private method and return a demo list.
MainClass obj = new MainClass();
MainClass spy = PowerMockito.spy(obj);
PowerMockito.when(spy, method(MainClass.class, "inokePrivate"))
.thenReturn(list); // demo list which exists as a test class member.
Above calls into private method which in turns tries to call wrapperObj.callWrapperMethod() which resides in a different artifact and breaks there because some implementation it doesn't find there.
So I try to mock wrapperObj.callWrapperMethod.
WrapperClass wr = new WrapperClass();
WrapperClass spy1 = PowerMockito.spy(wr);
when(spy1.callWrapperMethod()).thenReturn(list) // demo list which exists as a test class member.
Above mocking again calls into actual implementation of callWrapperMethod() and breaks in there.
How can I prevent calling into actual implementation of wrapper method?
Few of the answers that helped me-:
Mockito:How to mock method called inside another method
Testing Private method using mockito
[UPDATE] -: as suggested as I did following-:
PowerMockito.doReturn(list).when(spy1).callWrapperMethod(); // This returns me demo list successfully.
But now when I call private method from PowerMockito control goes into invokePrivate method and again tries to call original callWrapperMethod instead of return list from spy version.
I suggest to not do it this way. Your private method should not retrieve the singleton factory object using a static method.
Static stuff breaks "easy" mocking; forces you to use "power" mocking; and thereby, creates more problems than it solves.
Change your code to use dependency injection. Do something like this:
class YourClass {
private final Factory factory;
public YourClass() {
this(Factory.getInstance(); }
YourClass(Factory theFactory) {
this.factory = theFactory;
...
This will allow you to use the second constructor in your unit test; to provide a (easily mocked) factory object for your class. Thereby you eliminate the whole need for PowerMock.
Long story short - when code is hard to test; change the code; and not the test. As a side effect, you are improving the quality of your code - because you loose the hard dependency on that singleton object.
And just to be complete: I also recommend to avoid "breaking" the Law of Demeter ( http://en.wikipedia.org/wiki/Law_of_Demeter ): if your class needs the wrapper; then it should hold a wrapper object; if it needs that factory; then it should hold a factory object. But you should not hold one object ... to retrieve another object from there, to run something on that second object. As you see - doing so leads exactly to the sort of problem that you are facing.

Test Method Called Without Having Argument In Test Class

I have a class which takes a message with payload String.
The payload is then split and used to create an Entity which is passed to DAOInterface to persist.
How can you test the call daoInterface.insert(entity) has been made?
To Mock the DAOInterface and then verify the call to DAO requires the entity in the test class i.e.
verify(daoInterface).insert(entity);
Is this bad design i.e. creating the entity at this stage? Should the Sting[] split be passed to the DAOImplementaion and initialized there. Example problem,
public class ServiceClass {
#AutoWire
private DAOInterface daoInterface;
public void serviceMessage(Message<String> message) {
MessageHeaders mh = new MessageHeaders(message.getHeaders());
String[] split = ((String) mh.get("payload")).split("_");
code omitted
...
String type = mh.get("WhatType");
Entity entity = new Entity(split[0], split[1], split[2]);
if (type.equals("one"))
{
daoInterface.insert(entity); //How to test?
}
else
{
if (type.equals("two"))
{
doaInterface.modify(entity); //How to test?
}
}
}
}
You can verify with Mockito Matchers.
If you only care that the method is called with some Entity, you can verify that with
verify(daoInterface).insert(any(Entity.class));
If you care about which Entity, and the Entity class has an equals method, you can make an entity that should be equal to the one created and verify with
verify(daoInterface).insert(eq(expectedEntity);
If it's more complex than either of these cases, you can also write your own argument matchers.
The easiest thing you can do is injecting another collaborator to the service which will transform payload to Entity. This way you can keep control on object creation (Inversion of Control). Something like the example below injected to the ServiceClass should do the job:
interface PayloadTransformer {
public Entity transform(String payload);
}
This way your code will be easy to test and you split responsibilities which is usually a good thing. Have a look on Single Responsibility principle
Pushing transformation logic down to dao is almost never a good idea.
BTW. you can write else if without additional brackets and indentations. It's more readable like:
if (a) {
// do something
} else if (b) {
// do something
} else {
// do something
}
The last advice ServiceClass is really poor name for class. The word class is redundant here. Just name it Service, EntityService, MessageService or something which fits your case well.
I wouldn't name field with suffix *Interface as well. Underneath is some implementation injected, I assume. Better name it entityDao or just dao. It's up to you though :)
If you use a test framework like PowerMock, you can invoke private constructors and private methods in your test. This makes it easy to inject mock objects like a mock DAOInterface so you can retrieve it later and test it's been called.
For example, in PowerMock, to call a private constructor:
public class ServiceClass{
#Autowire
private final DAOInterface dao;
public ServiceClass() {
}
private ServiceClass(DAOInterface dao) {
this.dao = dao;
}
}
You simply do:
PrivateConstructorInstantiationDemo instance = WhiteBox.invokeConstructor(
PrivateConstructorInstantiationDemo.class,
new MockDAOInterface() );
So if you're using a dependency inject framework like above, this dovetails nicely. You don't normally have the dependency injection working during test, since it usually requires booting a large chunk of code with a lot of configuration.
By adding a single private constructor, you avoid breaking encapsulation, but you can still inject your mock object into the code during test with a test framework like PowerMock. This is considered best practice.
You could break encapsulation and add publicly accessible methods or ctors to the SeviceClass, but if you don't need them for your design it's not good practice to add them only for test. That's why people put such effort into bypassing encapsulation in frameworks like Mockito and PowerMock. It's not just a dodge around private code, it's because you want to keep the encapsulation while still being able to test.
EDIT:
If you're not familiar with making mock objects, you should do some Google searches on the subject. It's very common and a good skill to have. With the above code, you could make your own mock object. But making mocks is so common that most test frameworks will do this for you.
For example, in PowerMock, I just looked at their page on making mocks here. You can make a mock like this
DAOInteface myMock = createMock(DAOInterface.class);
You can then ask the mock to verify that methods are called:
expect(myMock.someMethod());
Now the mock 'expects' that method to be called, and if it isn't, it'll generate an error for your test. Pretty sweet actually.
You can also return values from a call:
expect(myMock.insert()).andReturn("Test succeeded");
so your code would then see the value "Test succeeded" when it called that method. I don't see that 'insert' does return a value, that's just an example.

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.

Can we mock a method in service while testing the service itself?

I am working on a project where I am using MyBatis annotations as persistence framework. Therefore, I have to create an interface for the 'mapper' and compose the mapper in the service like :
class XYZServiceImpl{
public XYZMapper getXYZMapper(){
return SessionUtil.getSqlSession().getMapper(XYZMapper.class)
}
}
Now while unit testing the service with Mockito, I am trying to inject a mock for the mapper. But since I am injecting mock in an instance of XYZService, how can mock a method of the service itself, in this case getXYZMapper() is what I am trying to stub. Although I have got a solution of creating the instance XYZMapper in the service and not call on demand like the above code does something like :
Class XYZServiceImpl{
XYZMapper mapper;
public void useXYZMapper(){
mapper = SessionUtil.getSqlSession().getMapper(XYZMapper.class);
}
}
But that would bring a lot of code changes (ofcourse I can refactor) but is there a way to achieve without having to make code changes?
Also what would be a 'purist' way to have a mapper instance in the class is it the method 1 that is better than method 2 in terms of performance?
EDIT : Here XYZMapper is an interface. Something like :
public interface XYZMapper{
#Select("SELECT * FROM someclass WHERE id = #{id}")
public SomeClass getSomeClass(int id);
}
EDIT : I am facing a similar situation but with a variance that I have a service that I do want to test like XYZServiceImpl. Now it has a method getXYZDetails() which has a lot of business logic handled within the service. Now if getXYZDetails looks like the following :
public XYZDetails getXYZDetails(int id){
XYZDetails details = new XYZDetails();
details.set1Details(fetchSet1Details(id));
//Perform some business logic
details.set2Details(fetchSet2Details(id));
if(details.set2Details() != null){
for(int i = 0; i < details.set2Details().size(); i++){
flushTheseDetails(i);
}
}
.
.
}
Kindly notice that fetchSet1Details(), fetchSet2Details(), flushTheseDetails are public service, public and private service respectively.
I want to know of a method that can mock/stub these methods while testing getXYZDetails() thus enabling me to
There are several options you can use.
Inject dependency
This works only for simple methods like getXYZMapper when method only returns external dependency of you object. This may require to create new XYZServiceImpl instances if for example mapper is bound to connection which is opened per request.
Encapsulate method behavior in object
Another way to achieve similar result is to use a factory or service locator
like this:
public class XYZServiceImpl {
public XYZServiceImpl(XYZMapperFactory mapperFactory) {
this.mapperFactory = mapperFactory;
}
public XYZMapper getXYZMapper() {
return mapperFactory.getMapper();
}
}
This will allow you easily substitute factory in test with implementation which returns mock mapper.
The similar approach can be used for other methods fetchSet1Details, fetchSet2Details, flushTheseDetails that is moving them to other class or classes. If the method contains complex (and may be loosely related) logic it is a good candidate to be moved in separate class. Think about what these methods do. Usually you can move some essential and unrelated part of them to other class or classes and this makes mocking them much easier.
Subclass
This is not recommended but in legacy code sometimes is very helpful as a temporary solution.
In your test subclass you class under test and override methods you need:
#Test
public void someTest() {
XYZServiceImpl sut = new XYZServiceImpl() {
public XYZMapper getXYZMapper() {
return mapperMock;
}
public Whatever fetchSet1Details() {
return whateverYouNeedInTest;
}
}
sut.invokeMethodUnderTest();
}
The only thing you may need to do is to change access modifier of private method to package-private or protected so you can override them.
Spying
This method in also discouraged but you can use mockito spies:
XYZServiceImpl realService = new XYZServiceImpl();
XYZServiceImpl spy = Mockito.spy(realService);
when(spy.fetchSet1Details()).thenReturn(whaeveryouneed);
when(spy.getXYZMapper()).thenReturn(mockMapper);
spy.methodUnderTest();
I would suggest the "purist" way of doing this is to accept an XYZMapper instance in your constructor and store it in a local field.
In production use, you can pass an e.g. SQLXYZMapper, which will interact with your database. In test use, you can pass in a mocked object that you can verify interactions with.

How to mock Objects that are not passed as arguments

Imagine the following class
public class ClassToBeTested{
private AnotherClass otherClass;
public void methodToBeTested(){
otherClass = new AnotherClass();
String temp = otherClass.someMethod()
// ...some other code that depends on temp
}
}
Now, if methodToBeTested was designed to accept an instance of AnotherClass I could easily create a mock of AnotherClass and tell Mockito to return a value i prefeer when someMethod() is called. However as the above code is designed AFAIK it's not possible to mock AnotherClass and testing this method will depend on what someMethod() returns.
Is there anyway I can test the above code without beeing dependent on what someMethod() returns using Mockito or any other framework?
If available you can use the Spring ReflectionTestUtils setField method:
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/util/ReflectionTestUtils.html#setField%28java.lang.Object,%20java.lang.String,%20java.lang.Object%29
If not write your own its pretty straight forward using reflection, some info here:
http://www.java2s.com/Code/Java/Reflection/Setprivatefieldvalue.htm
Something like the below, you will need additional error handling to get this to work properly:
public void setField(Object obj, String fieldName, Object value) {
Field f = obj.getDeclaredField(fieldName);
f.setAccessible(true);
f.set(obj, value);
}
It can then be called like this:
setField(objUnderTest, "fieldToSet", mockObject);
edit
I have just noticed that you are instantiating it inside the method. If that is absolutely necessary then you should follow the possible duplicate link posted by cyroxx.
Although that practice is often a sign of bad design so if you can take it out I would.
Setting the field by reflection as suggested in the other answer will work.
But if you're doing this sort of thing often, I'd recommend PowerMock (in conjunction with Mockito) or JMockIt to achieve this. Both allow you to mock constructors, statics, final fields... in short, just about anything. Very useful with legacy code.
However, when you're writing new code, and your class has a dependency on another class that you want to isolate in this way, you should consider changing the design so that the other object is passed in to your class instead of being instantiated by it. Search for "Dependency injection" and you'll find plenty...
As a quick fix, I usually wrap the call to new:
protected newAnotherClass() { return new AnotherClass(); }
That way, I can overwrite this method from a unit test. It's dirty but it's quick :-)
Here is a JMockit test which does what you want, very simply:
#Test
public void testTheMethodToBeTested(#Mocked final AnotherClass dep)
{
new NonStrictExpectations() {{ dep.someMethod(); result = "whatever"; }};
new ClassToBeTested().methodToBeTested();
new Verifications() {{
// verify other calls to `dep`, if applicable...
}};
}

Categories