Mocking a dependent class using Mockito in JAVA - java

I am quite new to Mockito. I apologise if my question sounds sill. I have a standalone JAVA application for which I have to write Unit test cases using JUnit and Mockito. The important thing is that I cannot change the code as it has been written by someone else and Integration testing has been completed. I have tried to search for similar questions, but couldnt find anything. Solutions suggested in somewhat similar questions, didnt work :(
I have attached the flow control diagram.I want to mock the dependent classes. For example when I am Unit testing 'Class 1 --> Method 1', I want to mock the output of 'Method 2 in Class 2' WITHOUT CALLING it. I have tried to use Mockito.when and Mockito.doReturn. Both call the dependent methods.
Can someone please suggest me some ideas to achieve this ?
//Pseudocode of Class 1
public class Class1 {
public boolean method1() {
Class2 c2 = new Class2();
boolean b1 = c2.method2();
}
}
//Pseudocode of Class 2
public class Class2 {
public boolean method2() {
Class3 c3 = new Class3();
boolean b2 = c3.method3();
}
}
... Likewise same for Class 3, 4 and 5

What you're being asked to do is write unit tests for logic which was written by someone who knows absolutely nothing about writing code for test-ability. Probably a developer who's been writing code for a very long time, does things in an "old school" way and thinks he's way too important to write unit tests. Whoever wrote the logic you're testing needs to go back to school and learn some new tricks.
Anyway that doesn't help you, so you can still unit test this logic, it's just more of a pain. Mockito alone can't do it, you need "PowerMockito" which will let you mock the construction of Class2.
First things first you need to add 2 new test dependencies to your project "powermock-api-mockito"+"powermock-module-junit4".
A test class for you case would look something like:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Class1.class)
public class Class1Test {
private Class1 testSubject;
#Mock
private Class2 class2;
#Test
public void testMethod1() throws Exception {
testSubject.method1();
verify(class2).method2();
}
#Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
PowerMockito.whenNew(Class2.class).withNoArguments().thenReturn(class2);
testSubject = new Class1();
}
}
So as you can see PowerMockito lets you mock out construction on new Class2 instances by using PowerMockito.whenNew(), this will only work if you've "prepared" Class1 using the annotation #PrepareForTest(Class1.class) otherwise Class1 can't be injected with the mock Class2 instance. Hopefully that points you in the right direction? On a side note, if you're a junior developer being asked to write unit tests for a more senior developer get out now, your development team is rotten!

Sometimes, code is not written to be testable.
Especially calling constructors inside methods or other constructors is a big issue for unit testing and mocking.
If you do not use factories or dependency inversion / dependency injection in any way, you will have a very hard time testing the code. This is one of the reasons why CDI is so popular.
Anyways, being asked to write Unit Tests after Integration Tests are already in place is kind of a bad smell. You should have written the unit tests first. If you follow Test Driven Development (TDD), you should have written your test even before you actually wrote your class. This way, it would be impossible to write classes that are hard to test.
But what to do on your already messed up situation?
I recommend to refactor your code. Instead of calling a constructor inside your methods, pass an instance into your method, or provide a field in the class in order to be able to mock it.
Reconsider the scope of your unit test. It should only test a single class. Everything else, all the dependencies should be mocked.

Related

In Java unit testing, how to mock the variables that are not injected but created inside the to-be-tested class?

For example, the class to be tested is
public class toBeTested {
private Object variable;
public toBeTested(){
variable = someFactory(); // What if this someFactory() sends internet request?
// Can I mock "variable" without calling
// someFactory() in testing?
}
public void doSomething(){
...
Object returnedValue = variable.someMethod(); // In testing, can I mock the behavior of
// this someMethod() method when
// "variable" is a private instance
// variable that is not injected?
Object localVariable = new SomeClass(); // Can I mock this "localVariable" in
// testing?
...
}
}
My questions are as stated in the comments above.
In short, how to mock the variables that are not injected but created inside the to-be-tested class?
Thanks in advance!
Your question is more about the design, the design of your class is wrong and it is not testable, It is not easy (and sometimes it is not possible at all) to write a unit test for a method and class that have been developed before. Actually one of the great benefit of TDD(Test Driven Development) is that it helps the developer to develop their component in a testable way.
Your class would have not been developed this way if its test had been written first. In fact one of the inevitable thing that you should do when you are writing test for your component is refactoring. So here to refactor your component to a testable component you should pass factory to your class's constructor as a parameter.
And what about localVariable:
It really depends on your situation and what you expect from your unit to do (here your unit is doSomething method). If it is a variable that you expext from your method to create as part of its task and it should be created based on some logic in method in each call, there is no problem let it be there, but if it provides some other logic to your method and can be passed as parameter to your class you can pass it as parameter to your class's cunstructor.
One more thing, be carefull when you are doing refactoring there will be many other components that use your component, you should do your refactoring step by step and you should not change the logic of your method.
To add another perspective: If faced with situations in which you have to test a given class and aren't permitted to change the class you need to test, you have the option to use a framework like PowerMock (https://github.com/powermock/powermock) that offers enhanced mocking capabilities.
But be aware that using PowerMock for the sole purpose of justifying hard to test code is not advisable. Tashkhisi's answer is by far the better general purpose approach.

Mocking constructor using powermock on the class which needs to be tested

I am able to mock a constructor call using powermock from inside a class which I want to test. This works when I add the class I want to test in #PrepareForTest. But once I add my class there, even when the test cases pass, the coverage is being shown as 0 in the coverage plugin.
When I remove my class from #PrepareForTest, of course, coverage starts showing up for other test cases but the test case in which I have to mock constructor call fails. Not sure what to do about this.
Class A
{
MyObject o;
A(){
//some other code
o = new MyObject();
//some other code
}
public void process(){
//some code
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.class)
Class TestA{
#Test
public void test1()
{
MyObject mocked = Mockito.mock(MyObject.class);
PowerMockito.whenNew(MyObject.class).withNoArguments().thenReturn(mocked);
A a = new A();
a.process();
//Assert as per test case
}
}
In coverage tool, coverage shows as 0 however, unit test passes and I checked in debug mode that it was covering all the statements of class A.
In coverage tool, coverage shows as 0 however, unit test passes and I checked in debug mode that it was covering all the statements of class A.
Coverage tools rely on manipulating the executed byte code.
So does PowerMock, when you mock static/new.
This can quickly lead to all sorts of problems. For JaCoCo, there seems to be a solution around offline instrumentation. Where, I also remember: some other person asked about that some time back, and in the end gave up, because he couldn't get "offline instrumentation" to work either.
For any other framework, I have to repeat old advice: consider to invest your time to learn how to write easy-to-test code. Because if you would do that, you would not need to use PowerMock(ito) in order to test it.
Your code is hard-to-test because of that new() statement in the constructor. Simply don't do that. Either use dependency injection via #InjectMocks, or have a test-only constructor that takes the required object.
Long story sort: when you write your own, new code, and you think you need PowerMock to test it, then you are doing something wrong.
I think you can do without Powermock here. If you Spy on class A and mock the getter you should end up with the same result and most likely have your coverage correct:
#Test
public void test1(){
MyObject mocked = Mockito.mock(MyObject.class);
A spyA = Mockito.spy(new A());
doReturn(mocked).when(spyA).getMyObject();
...
}

Mock a New Object instance in a Abstract Class

I have a AbstractDao class, where I am instantiating Rest Fore API. I am not able to mock the new forceAPI(config) in Power Mock. Please suggest.
public abstract class AbstractDao {
#Inject
private Configuration configuration;
public ForceApi getForceAPI() {
ApiConfig config = new ApiConfig();
config.setClientId("test");
config.setClientSecret("test");
config.setUsername("test");
config.setPassword("test");
config.setLoginEndpoint("test");
return new ForceApi(config);
}
}
I am trying to do in this way but it's not working.
My DAO class is extending Abstract DAO class
#RunWith(BlockJUnit4ClassRunner.class)
public class SalesForceDaoImplTest {
#InjectMocks
private SalesForceDaoImpl salesForceDao;
#Mock
private ForceApi forceApiMock;
#Mock
private ApiConfig apiConfigMock;
#Mock
private Configuration configMock;
#Mock
JsonObject jsonobject;
#Before
public void setup() {
initMocks(this);
when(configMock.getAppConfiguration()).thenReturn(jsonobject);
when(jsonobject.getString(anyString())).thenReturn("test");
when(salesForceDao.getForceAPI()).thenReturn(forceApiMock);
when(new ApiConfig()).thenReturn(apiConfigMock);
when(new ForceApi(apiConfigMock)).thenReturn(forceApiMock);
}
Probably this is a late reply, but I believe it still can be useful to some of us, programmers.
Disclaimer: I've never worked with PowerMockito but I've used PowerMock quite a lot
As for troig's suggestion:
PowerMock driven unit test assumes that you'll run with a dedicated runner:
#RunWith(PowerMockRunner.class)
In this case this clashes with #RunWith(BlockJUnit4ClassRunner.class) stated in the question, so the "slot" for RunWith is already occupied.
This particular one can still be resolved by running recent versions of power mock as a JUnit's rule (I assume you run JUnit) You can find an example of doing this here
But bottom line this is one of known issues with power mock.
There are other issues as well which basically made me to come to conclusion that the power mock should be avoided and should not be used in new project (and Power Mockito as well):
The unit test with power mock is slow (much slower than, say with EasyMock if it could be rewritten for using that)
The Power Mock sometimes instruments the byte code incompatible with tools like jacoco code coverage and as a consequence sonar doesn't cover classes unit tested with power mock or at least does it wrong
Surefire plugin responsible for running tests in maven has a feature of running multiple unit tests in parallel. Sometimes with power mock its not possible.
Even IntelliJ sometimes fails to run suits that contain power mock tests.
But the most important thing is that when you have to use tools like power mock, probably the code can (and should) be refactored to be more clean and easy-to-understand. Regarding your particular question:
Your class violates the coding principle that says that the class should not take care of dependencies of itself. Here DAO actually "constructs" and configures another (external) service for a later use.
I suggest you to watch an excellent lecture of Misko Hevery about clean code to better understand what I mean
So again, in your example. Its much better to maintain the ForceApi as a dependency constructed by Dependency Injection framework (I see that you already use #Inject so you're on the right track)
Take a look at this implementation:
public abstract class AbstractDao {
#Inject // this one is constructed and injected by your favorite DI framework in real use cases
private ForceApi forceApi;
public void doSomething() {
// do your dao stuff here
forceApi.callSomeAPIMethod();
// do your dao stuff here
}
}
Now for unit tests you don't really need power mock anymore. Its enough to use a simple Mock or even Stub depending on situation. All you need is to provide a constructor that will take a parameter of type ForceApi or maybe a setter (you can consider make it package private so that noone would be able to call it outside the test).
I don't have enough information out of your question, but the design I've offered probably can eliminate the need to have an Abstract class for the DAO, which is also can be helpful in some cases because inheritance sometimes can be a pretty heavy 'obligation' to maintain (at least think about this). And maybe in this case the inheritance is done only to support this getForceAPI behavior. In this case as the project grows, probably some methods will be added into this AbstractDAO just because its convenient to do so, but these methods will 'transparently' be added at this point to the whole hierarchy to all DAOs. This construction becomes fragile, because if at least one method changes its implementation the whole hierarchy of DAOs can potentially fail.
Hope this helps

how to unit test methods with dependencies

I need to create some unit testing for my application but I am not sure how to proceed and I couldn't find anything of help online. What I want to know is how to test an app where there are many methods dependent on a few others.
e.g.
public class foo(){
public void doIt() {
boz();
bar();
biz.baz(); //from another class
}
public void bar(){
...
}
public int boz(){
...
}
}
so in a scenario like the one presented above one would think that unit testing the doIt method would be sufficient since it is going to fail anyway if something is wrong with the methods called inside it.
Although, I am not sure if we can consider this to be unit testing as this tests the functionality of more than just an entity. In addition, if the test on the doIt method fails it is going to be really hard to tell where the error occurred especially in a case with many dependencies - doesn't that defy the meaning of unit testing?
So far the only approach I have thought is to start by testing the dependencies first (i.e. bar boz baz) and then the doIt method. That way, if the test suite gets to doIt with no errors and fails means that there is something wrong with the code implemented inside that method and not inside its dependencies.
BUT, is this the right way of doing it?
To test doIt() method without having to invoke the real implementations of bar() and baz(), use a Spy in Mockito:
Mockito spy documentation
If bar() is really void, you can do something like this:
foo f = spy(new foo());
doNothing().when(foo).bar();
Better is if you can inject your dependencies (ex: biz) as mock objects and test your foo class directly.

what's the point using Mockito to mock objects? [duplicate]

In the program below, I am trying to use mockito with junit in my test case. But I don't see how Mokito is helping to create objects for my test? I don't see anything special here as it seems as if mokito is instantiating the actually object.
public class TestCase1{
#Mock
MyClass myClass;
public void setup(){
MokitoAnnotations.initMoks(this);
}
#Test
public void testAddition(){
when(myClass.add(2,2)).thenReturn(20);
assertEquals(4,myClass.add(2,2));
}
}
My actual class (MyClass.java)
public class MyClass{
public int add(int x, int y){
return x+y;
}
}
Is it mocking an object, the same as injecting(DI) an object? I appreciate your help!
Your test doesn't test any of your code. It tests that Mockito works fine.
When I introduce the concept of mocking, I take this example: suppose you build a detonator, and want to test it. You could of course use the detonator with a real bomb, and see if the whole block explodes when you use the detonator. But that isn't very practical. BTW, maybe you don't even have a bomb at your disposal. Maybe your colleague is still building it.
So you use a mock bomb. Note the important point: to test the detonator, you use a mock bomb. Not a mock detonator. What is mocked is the dependency of the class under test. Not the class under test itself.
What is a mock bomb? It's just a fake bomb that doesn't do anything. All it does is allowing to verify if has been asked to explode or not. So your code to test the detonator would be like this:
// create a mock bomb:
Bomb mockBomb = mock(Bomb.class);
// create a real detonator, but tie it to the mock bomb:
Detonator detonator = new Detonator(mockBomb);
// test the detonator. Since it's tied to a mock bomb, the block
// won't explode
detonator.pressTheRedButton();
// check it the mock bomb has been asked to explode, as it should
// if the detonator works correctly
verify(mockBomb).explode();
Now if the test passes, you know that all the internal circuitry that is used in pressTheRedButton() works fine and eventually tells the bomb to explode. So you know that, when used with a real bomb, the real bomb will be asked to explode as well when pressing the red button.
Now let's come back to the real world: you want to test a service, and this service uses a DAO that needs a database, populated with data, to run fine. To test your service, you can simply mock the DAO, and verify it works fine. The mock DAO can also be used as a stub, i.e. an object that returns what you tell it to return in the test, instead of actually querying the database. That's what you're doing in the code in your question: you're telling the mock MyClass instance that, when add() is called with 2 and 2 as arguments, it should return 4.
This makes the test easier to setup, faster to run, and independant from the actual code of the DAO, which is not what you want to test in the unit test of the service.

Categories