I am writing unit tests with JUnit and Mockito. Let's say I have following test class:
#Mock(name="myService")
private myServiceClass myService;
#InjectMocks
private myClassIWantToTest classUnderTest;
final myModelClass myModel = new myModelClass();
#Before
private void setUp(){
MockitoAnnotiations.initMocks(this);
}
#Test
private void testSomething(){
myModel.setCode("someCode");
final MyDataClass myData = new MyDataClass();
myData.setCode("someCode");
doReturn("someCode").when(myModel.getCode());
doReturn(myModel).when(myService.getModelByCode("someCode"));
assertEquals(classUnderTest.getDataByCode(eq("someCode")), myData);
verify(myService.getModelByCode(eq("someCode")), atLeastOnce());
}
The method getDataByCode from my classUnderTest converts the Model into Data and it should have the same code. What is a bit blurry to me is that unit tests should encapsule the classUnderTest from all dependencies. But now I have a problem. I use the setter methods myData and myModel to set a value. The thing is I put a DoReturn in there for myModel, but the problem is, that it's not a injected Mock. The method I try to test unfortunately doesn't have a field, it initializes this inside the method, so I can't really address it.
And the main thing is, when the setter of for example myModel doesn't work anymore or so, my test as shown above, wouldn't work anymore. I guess I have three questions:
How hard do I need to isolate the test class? Don't I need to use the setters for the assertEquals?
Is there another way to deal with objects, which are initialized inside a method I want to test? What is the best way to approach such a matter?
Also, what would be a good pattern for structuring this? I currently initialize my expected myData result inside a test method. The thing is that this is a rather short and easy example, but I have classes where I have tons of objects and methods.
Sounds like your main problem is the design of the class you want to test. But a few things before:
myModel.setCode("someCode");
doReturn("someCode").when(myModel.getCode());
This doesn't make sense. It's not a mock, so do...when doesn't make sense here. And if it was a mock, calling the setter would be useless.
assertEquals(classUnderTest.getDataByCode(eq("someCode")), myData);
Also strange. You want to call getDataByCode, why the eq? Do it. Call it. Write:
assertEquals(classUnderTest.getDataByCode("someCode"), myData);
Mockito-Matchers are good when you want to verify something but normally you don't use them as parameters for real method calls.
verify(myService.getModelByCode(eq("someCode")), atLeastOnce());
Does this code really compile? Shouldn't it be ...
verify(myService, atLeastOnce()).getModelByCode(eq("someCode"));
So, it would be a good idea to actually isolate your unit tests as far as you can. The less external problems you are inviting into your test, the better the test can be.
The method I try to test unfortunately doesn't have a field, it
initializes this inside the method, so I can't really address it.
This simply sounds like a code smell, but without the actual code in question, it's hard to say...
Related
I have a problem with mockito while mocking up the final field of a class can you guys help on that
public class Product{
public final String VALUE= "ABC";
public String someMethod(){
if (!VALUE.equals("ABC")){ ## IF NOT WORKING
//inside if condition
}else{
//inside else condition
}
}
}
//Test Class
#test
public void test_someMethod(){
Product product = Mockito.mock(Product.class,"Product");
Field field = Product.class.getDeclaredField("VALUE");
field.setAccessible(true);
ReflectionUtils.setField(field, product , "XYZ");
}
Now, when running in debug mode this shows me changed value to XYZ but dosen't work with if condition always goes in else block despite shows XYZ in debug mode.
Basically, you are going down the very wrong rabbit hole here. It is not a good idea to throw together so many things.
First of all, Mockito (and all the other mocking frameworks) are intended to be used for behavior, not state. In other words. Albeit your mock object actually has that field, keep in mind: it still is a mock object. You won't find much documentation or tutorials telling you what the mocking framework will do about fields, and field values of mocked objects.
Worse, and the real problem: you do not mock your class under test. You use mocks to gain control over other objects that your code under test is using. Mocking and testing the same object simply does not make (much) sense!
Then: do not use reflection together with "mocking" based unit testing, especially not to "reflect" on mocked objects. As said: these frameworks do whatever they think is necessary, so even if some code works today, there is a realistic chance that a new version of Mockito might change such internals, and cause such code to fail in the future.
Next, note that your code is nonsensical to begin with:
public final String VALUE= "ABC";
public String someMethod(){
if (!VALUE.equals("ABC")){ ## IF NOT WORKING
VALUE is always ABC, so you always end up with if(!true). There is no point in having that if statement in your code then.
So, if you really need such kind of a switch, you could make it a method call, like:
public String someMethod(){
if (reallyDoIt())) ...
with
boolean reallyDoIt() { return ...
The point is: now you could use Mockito's spy concept to test your someMethod() call. By doing so, you can instruct Mockito to "really" call someMethod() but to return a fake answer for reallyDoIt(). For more details, see here for example.
Beyond that, I strongly recommend that you step back and read a good tutorial about Mockito, like the one from vogella. Simply because your code implies that you do not really understand how to use mocking frameworks in unit testing.
Thanks.. for detailed explanation. But for me here limitation is not to change the base code (I.e somemethod()).
I have a private method in my java code which needs to be invoked twice. I am writing junits using Powermock. While mocking the said method I need two different results for two different invokations.
//I have tried:
PowerMockito.doReturn("MyString1").doReturn("MyString2").when(spy,"getresult",Mockito.anyString());
//But when() is not accepting anything else than the spy object.
PowerMockito.doReturn("MyString1").doReturn("MyString2").when(spy).getresult(Mockito.anyString());
//when() is not letting to use the method getresult as this getresult method is declared private.
CODE
Class A{
String firstString="abc";
String secondString="def";
String result1=getresult(firstString);
String result2=getresult(secondString);
private String getresult(String arg1){
//My code here;
return "AnyString";
}
}
JUNIT
//Declarations
#InjectMocks
A a;
.......
#Test
public void ATest(){
....
/*Suppose I want "MyString1" and "MyString2" as result for calling the method "getresult" for result1 and result2 in Class A*/
A spy=PowerMockito.spy(a);
PowerMockito.doReturn("MyString1").when(spy,"getresult",Mockito.anyString());
....
}
// Please overlook the typos
I am getting compilation error while using the code that I tried.
As written in the comments of code, I am expecting two results "MyString1" and "MyString2" in the two successive method calls as shown in the code.
Thanks in advance. Any other approach to achieve the results is appreciated.
Let me start with the note that the main reason to use PowerMock is to help testing the Legacy applications. There is literally no place for the PowerMock in a new code. Need for a PowerMock in a new code indicates serious problems in the design.
One of the benefits of unit testing is that the tests provide feedback on your design. If writing such test is overly awkward, fragile or not possible (without PowerMock) you should reconsider your design.
One of the things you can do to test such code is to extract the private method into a separate class and provide it as a dependency. Then you can mock it easily. But you should still test the extracted logic which depends on why you could not setup the test in the first place. You may need integration test or some other approach.
I usually do not test private methods separately. They will be tested by the public method which is calling this private method. If there are multiple flows, write multiple tests in a way where all code paths in the private method are tested.
However the following link shows how to test private methods.
https://dzone.com/articles/mock-private-method
I have a method
public TaskProperty addTask()
{
/*some operations
*
*/
mapToProperty();
}
private TaskProperty mapToProperty()
{
/**some op's**/
}
How to write unit test case for the addTask() without allowing the control to go inside mapToProperty() method.
How to mock the private method mapToProperty()?
The fact that you want to do this ... doesn't make it a good idea:
private methods represent "internal implementation" details. Excluding them from a test ... means that your test needs to know about this private method. But your tests shouldn't know anything about your private implementation details. They should not need to care.
In other words: your unit tests should only care about the public interface of your class(es). Thus: you try to write all your code in a way that you can test those public methods without the need to "disable" something other in the class you are testing. Meaning: either try to rewrite your private method so that you can call it from any unit test; or if that is not possible, move the corresponding behavior into another class; and then provide a mocked instance of that class to your method under test.
Long story short: your question implies that you want to fix a "bad design" by using the "mocking framework hammer" to "massage" the symptom. But it a symptom; and the underlying problem is still there, and affects your code base. So spend your time fixing the real problem; instead of working around it!
And just in case you still prefer to mock that private method; I would rather suggest to look into a mockito spy to do that (although PowerMock also allows for such kind of test, see here)
Currently trying to write unit tests for a complicated system that uses a constructor within one of its method that takes itself as the parameter to inject into a database context and retrieve the correct object from the correct environment.
Trying to use Mockito to emulate this, and make it return a test object instead of it going to try and find it from the database; but i'm stumped as to how to make it work with traditional techniques and #InjectMocks + #Mock annotations.
The essence of the code is below:
public FooService{
public String fooFindObject(FooDefinition fooDef) throws FooDefinitionException{
FooFinder theFooFinders = new FooFinder(this);
Foo fooObj = theFooFinders.findFoo(fooDef);
//Logic to be tested inside here that will throw exception upon bad foo definitions
return fooObj.trackingId();
}
How could I mock this FooFinder object and make it return my own testing foo object so I can test the definition obj. Mockito is being used, and the possiblity of rewriting this code to use get/setters of the FooFinder obj is not allowed - it's not my code and I'm just there to test it.
There is a library that extends upon Mockito: PowerMockito.
It allows you to do quite some more hacking than the usual Mockito. It's pretty sweet, but the thing is, if you need PowerMockito, your design usually smells.
I would definetely refactor your design. But if you can't do this for any reason, please take a look at constructor mocking with PowerMockito:
http://benkiefer.com/blog/2013/04/23/powermockito-constructor-mocking/
Lets say I have a method that looks like this:
public static String[] parseFoo(Foo anObject){
Foo anotherObject = parseFoo2(anObject);
...
}
private static Foo parseFoo2(Foo anObject){
...
}
and both methods are in the same class. parseFoo2 is just a helper method that helps parseFoo get some stuff done. I'm trying to test the method parseFoo. Is there anyone in EasyMock that I can specify a return value on that private method call for parseFoo2 like the way I can specify instance method calls for an object with
EasyMock.createMock(...);
anObject.expect(...).andReturn(...);
because I want to test the public method, but I don't want to have to go into the private method and test the implementation inside.
Thanks
Don't do it.
One of the corner stones of a good unit test is that it should rely as little as possible on implementation details. Mocking out a private method is exactly that.
Why?
Because that makes your unit tests very brittle. Consider the situation where you come back to this code in a week and decide that you don't really need the method parseFoo2 and you actually want to inline its code. Or that you want to split this method into two or more smaller methods. All very valid refactoring practices- but they will break the unit test!
You don't want to be chasing unit tests each time you make a simple refactoring like that. Hence, it is considered bad practice to mock private methods.
If you find that you must mock out a private method, then you can use PowerMock.expectPrivate(). EasyMock is not capable of mocking private methods.
If you still want to use EasyMock, because changing it doesn't depend on you (work in an enterprise) you can use reflection to change the private field which your method returns, or any private field for that matter.
You can have these methods in a helper class for example. And use them as needed.