I have a java class that invoke a method via reflection. That method create database connection and perform database operations. i want to test my reflections code using junit. Is there any way to do that?
Please find my code snippet below.
Class DaoImpl {
public void setResult(String result) {
this.result = result
}
public String getResult() {
return this.result;
}
public void doDBoperation() {
Connection connection = getConnection();
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery("Select column_name from table");
if(rs.next()) {
result = "value";
}
}
}
Class ReflectionClass {
public void invoke() {
Class<?> noParam = {};
Class<?> clazz = Class.forname("DaoImpl");
Method method = clazz.getDeclaredMethod("doDBoperation", noParam);
method.invoke(clazz.getNewInstance);
System.out.println("This is it");
}
}
How to write JUnit test case for my ReflectionClass?
As #GhostCat suggested PowerMockito could be used to try to mock DaoImpl's constructor. Here's the code:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(ReflectionClass.class)
public class ReflectionClassTest {
#Test
public void invoke() throws Exception {
DaoImpl mockedDaoImpl = PowerMockito.mock(DaoImpl.class);
PowerMockito.whenNew(DaoImpl.class).withNoArguments().thenReturn(mockedDaoImpl);
new ReflectionClass().invoke();
Mockito.verify(mockedDaoImpl, Mockito.atLeastOnce()).doDBoperation();
}
}
But, it doesn't work. PowerMock doesn't manage to mock the constructor when invoked through reflection.
There is no real "pure unit test" way of testing *ReflectionClass**. Normally, you would do a unit test by providing a mocked instance of that class to your production code; then you could use the mocking framework to verify that the expected method was called.
But in your case, you created code that is simply hard to test (if you want to learn how to address that part, you might want to watch these videos). You are basically calling "new" directly in your production code; thus there is no way to insert a mocked object. And beyond that, you also can't mock those reflection methods.
The only option to maybe get this code tested would be to use Mokito together with PowerMock. But I am not an expert in that area, and can't promise you that it will work.
My recommendation to you: step back first and figure if you can get away from using reflection, or at least: to separate concerns here. Because as said: your production design looks weird; and instead of spending hours to get that somehow unit tested; you should rather spent a fraction of that time to improve your design! "Hard to test" typically means "design could be improved"!
Meaning: first you create an interface that denotes the function that you want to test. Then you separate your production code of ReflctionClass, like:
One part is responsible for providing an instance of that interface (and that code could be using reflection to do its job, if that is really required)
The other part then calls the method(s) you want to be called on that interface object.
By doing so, you get two parts that you can test independently of each other!
Edit: what I mean by "bad design" - why are you using reflection to do both - object creation and method invocation? You see, you could simply cast that created object to its correct class (at least if you have an interface defined there) and then do a ordinary method call on that typed object.
Related
I am fairly new to mockito framework. I've been reading upon multiple tutorials in regards to it. One of them I was following is this: https://www.tutorialspoint.com/mockito/mockito_first_application.htm
There is a statement creating a mock of Stock Service.
In this example, we've created a mock of Stock Service to get the dummy price of some stocks
My question is Stock Service is a real service class or mock service class you have to manually stand up for mimicking the real service class. I am a bit confused. Having basic understanding of junit framework. What I had practiced before was if there is a service class Foo then I used actual class that provides all the exposed methods.
public class Foo {
public Foo() { } // construtor
public String returnAddress(String userId) {
// ...
return dataAccesobj.getAddress(userId);
}
}
Calling foo.returnAddress(..) in unit test if I remember right.
The reason I am asking this question is while I was working with mockitoto create a test method for a class, I ran into a unique(?) challenge.
I started with a real service class which depends on its super class constructor to return its instance. The challenge I ran into was this super class constructor initiates DB connection and loading/parsing properties files which I do not need for my test. I was thinking about how to prevent DB connection and loading/reading prop files....
I thought I read from one of mockito tutorials you can isolate testing without having such services. I tried with #Mock and #Spy (not fully understanding well still what they are for..) but it didn't make a difference for output (maybe I misused those annotations).
So what I did was actually creating fake/mock class out of real service class (e.g. Foo) by simply copying it and renamed it as FooMock and put it in src/test/java folder in where unit test class is running from. I kept the mock class exactly same as the real service class except taking out unwanted logic such as db connection or loading/reading prop file for env specific. By doing that I was able to test one of exposed methods that read ldap directory...
I am sorry I got digressed but hope my point is clear at this point. I am not sure the way I handled this situation is right or wrong. I'd appreciate experienced engineers would clarify the way I handled the matter is acceptable in mockito way or not. If not, then plz advise me best way to handle it.
With Mockito,
a mock is an implementation of a wrapper class.
The mock object "wraps" the target of the mock
(the service in your example)
and allows you to define functionality of each method.
There are two mocked functionality options with Mockito;
call the wrapped method and don't call the wrapped method.
I don't know when it would make sense to call the wrapped method,
so I always use don't call the wrapped method.
After you create the mock,
use the Mockito.doReturn(returnvalue).when(mockObject).method(method parameters) method to mock functionality.
Edit: some more info.
I will assume that you are using junit v4.
The details of this will differ based on the the junit major release number,
but the actual work will be the same.
Use annotations to define your Mock objects (#Mock),
except in a few special cases.
This will create mocks of non-final classes,
abstract classes,
and interfaces.
Create a "before-test" method using the #Before annotation;
I traditionally name this method preTestSetup,
but the actual name does not matter.
Call MockitoAnnotations.initMocks(this) as the first line of code
in the "before-test" method.
This will find the #Mock annotations and instantiate a mock for each.
Use the ReflectionTestUtils.setField method to inject the mocks into your object (assuming that you don't have setter methods,
which I traditionally don't like).
Define the mocked functionality of each method using the Mockito.doReturn(returnvalue).when(mockObject).method(method parameters) technique.
Here is some example code
(caveat:
this should be fully functional,
but I did not compile it):
public interface MyService
{
String blammy(SomeParameter parameter);
}
public class UsesMyService
{
#Autowired
private MyService myService;
public String kapow(final SomeParameter parameter)
{
return myService.blammy(parameter);
}
}
public class UnitTestUsesMyService
{
private UsesMyService classToTest;
#Mock
private MyService mockMyService;
#Mock
private SomeParameter mockSomeParameter;
#Before
public void preTestSetup()
{
MockitoAnnotations.initMocks(this);
classToTest = new UsesMyService();
doReturn("Blam").when(mockMyService).blammy(mockSomeParameter);
ReflectionTestUtils.setField(
classToTest,
"myService",
mockMyService);
}
#Test
public void kapow_allGood_success()
{
final String actualResult;
actualResult = classToTest.kapow(mockSomeParameter);
assertNotNull(actualResult); // Not strictly necessary.
assertEquals(
"Blam",
actualResult);
}
}
I am working on spring based project and writing unit test case using JUnit + Mockito. I am facing a problem while stubbing boolean value to a private method of same test class (after changing access level to public, still I have failed to stub the boolean value).
Below code snippet shows the simulation of same problem
class ABC {
public String method1(User userObj){
String result = "";
if(!isValidUser(userObj.getSessionID())){
return "InvalidUser";
} else {
// execute some logic
}
return result;
}
private boolean isValidUser(String sessionId) {
// Here it calls some other class to validate the user
if (sessionId == null || UserSessionPool.getInstance().getSessionUser(sessionId) == null) {
return false;
} else {
return true;
}
}
}
Here, I would like to write a test case for method1(). In class ABC I have a method called isValidUser() which helps to identify the user with in a session by looking into a global session pool which holds all logged-in used details i.e. UserSessionPool.getInstance().getSessionUser(sessionId).
While testing method1(), the moment test controller triggers isValidUser(userObj.getSessionID()) I would like to return true from isValidUser() method, so that I can continue to test rest of the implementation logic.
So far I have tried following ways using spy and mocked object to call the isValidUser() method and try to return true but nothing worked well.
Using PowerMockito
PowerMockito.doNothing().when(spyed_ABC_ClassObject, "isValidUser", true);
or
PowerMockito.doReturn(true).when(cntrl, "isValidUser", Mockito.anyString());
Using Whitebox
Whitebox.invokeMethod(spyed_ABC_ClassObject, "isValidUser", Mockito.anyString());
Using Mockito.when
when(spyed_ABC_ClassObject.isValidUser(Mockito.anyString())).thenReturn(true);
or
Mockito.doNothing().when(spyed_ABC_ClassObject).isValidUser(Mockito.anyString());
The other answer is: fix your design instead of turning to the big PowerMock hammer.
Yes, PowerMock allows you to mock static methods. But you should understand: static is an abnormality in good OO design. You only use it when you have very good reasons. As it leads to tight coupling between your classes, and surprise: it breaks your ability to write reasonable unit tests. Yes, PowerMock works; but sometimes, it does not. When your classes grow, and you do more and more things "statically", because, you know, PowerMock will do the job ... be prepared for bizarre fails at some point, that can take hours to hunt down; without ever finding real bugs in your production code.
So, consider an alternative:
Do not use static method calls. And if there is some static method around that you can't touch; consider building a small interface around that.
Instead: use dependency injection and simply pass objects implementing some interface into your production code. Because you can mock such objects without the need for PowerMock(ito).
In that sense: you simply created hard to test code. Now you intend to fix that using PowerMock. The other way (much more reasonable in my eyes) is to learn how to write testable code in the first place. Here is a good starting point for that.
Can you please try this out.
#Before
public void setUp() {
UserSessionPool mockConnectionPool = Mockito.mock(UserSessionPool.class);
}
#Test
public void testName() throws Exception {
//given
PowerMockito.mockStatic(UserSessionPool.class);
BDDMockito.given(UserSessionPool.getInstance()(...)).willReturn(mockConnectionPool);
Mockito.when(mockConnectionPool.getSessionUser(Mockito.anylong())).thenReturn(something);
//then
PowerMockito.verifyStatic();
}
Hope this helps. Happy coding !
I have a few static util methods in my project, some of them just pass or throw an exception. There are a lot of examples out there on how to mock a static method that has a return type other than void. But how can I mock a static method that returns void to just "doNothing()"?
The non-void version uses these lines of code:
#PrepareForTest(StaticResource.class)
...
PowerMockito.mockStatic(StaticResource.class);
...
Mockito.when(StaticResource.getResource("string")).thenReturn("string");
However if applied to a StaticResources that returns void, the compile will complain that when(T) is not applicable for void...
Any ideas?
A workaround would probably be to just have all static methods return some Boolean for success but I dislike workarounds.
You can stub a static void method like this:
PowerMockito.doNothing().when(StaticResource.class, "getResource", anyString());
Although I'm not sure why you would bother, because when you call mockStatic(StaticResource.class) all static methods in StaticResource are by default stubbed
More useful, you can capture the value passed to StaticResource.getResource() like this:
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
PowerMockito.doNothing().when(
StaticResource.class, "getResource", captor.capture());
Then you can evaluate the String that was passed to StaticResource.getResource like this:
String resourceName = captor.getValue();
Since Mockito 3.4.0, an experimental API was introduced to mock static methods.
The following example code has been tested with Mockito 4.3.1 (testImplementation("org.mockito:mockito-inline:4.3.1), and JUnit Jupiter 5.8.2, OpenJDK 11.
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.util.UUID;
public class StaticMockTest {
#Test
void showCaseStaticMock() {
try (MockedStatic<StaticMockTest> staticMock = Mockito.mockStatic(StaticMockTest.class)) {
staticMock.when(StaticMockTest::getUUIDValue).thenReturn("Mockito");
Assertions.assertEquals("Mockito", StaticMockTest.getUUIDValue());
}
// Regular UUID
UUID.fromString(StaticMockTest.getUUIDValue());
}
public static String getUUIDValue() {
return UUID.randomUUID().toString();
}
}
Previous Answer, probably Mockito 1.x/2.x with Powermock 1.x/2.x
You can do it the same way you do it with Mockito on real instances. For example you can chain stubs, the following line will make the first call do nothing, then second and future call to getResources will throw the exception :
// the stub of the static method
doNothing().doThrow(Exception.class).when(StaticResource.class);
StaticResource.getResource("string");
// the use of the mocked static code
StaticResource.getResource("string"); // do nothing
StaticResource.getResource("string"); // throw Exception
Thanks to a remark of Matt Lachman, note that if the default answer is not changed at mock creation time, the mock will do nothing by default. Hence writing the following code is equivalent to not writing it.
doNothing().doThrow(Exception.class).when(StaticResource.class);
StaticResource.getResource("string");
Though that being said, it can be interesting for colleagues that will read the test that you expect nothing for this particular code. Of course this can be adapted depending on how is perceived understandability of the test.
By the way, in my humble opinion you should avoid mocking static code if your crafting new code. At Mockito we think it's usually a hint to bad design, it might lead to poorly maintainable code. Though existing legacy code is yet another story.
Generally speaking if you need to mock private or static method, then this method does too much and should be externalized in an object that will be injected in the tested object.
Hope that helps.
Regards
In simpler terms,
Imagine if you want mock below line:
StaticClass.method();
then you write below lines of code to mock:
PowerMockito.mockStatic(StaticClass.class);
PowerMockito.doNothing().when(StaticClass.class);
StaticClass.method();
To mock a static method that return void for e.g. Fileutils.forceMKdir(File file),
Sample code:
File file =PowerMockito.mock(File.class);
PowerMockito.doNothing().when(FileUtils.class,"forceMkdir",file);
I was trying to write unit test using jmocks and junit. (My Project uses core java- no frameworks-) I could not write unit test for some of my classes, by mocking external dependencies, when dependencies were initialized in a a no arg-constructor.
As i cannot provide the actual code, trying to explain the scenario by an example
public interface Apple {
String variety();
}
Implementation.
public class MalgovaApple implements Apple {
#Override
public String variety() {
return "Malgova";
}
}
Class to be tested
public class VarietyChecker {
private Apple apple;
VarietyChecker(){
this.apple = new MalgovaApple();
// instead of new, a factory method is used in actual application
}
public String printAppleVariety(){
String variety = apple.variety();
if(variety.length() < 3){
System.out.println("Donot use Code names- Use complete names");
return "bad";
}
return "good";
}
}
Junit test using jmock
public class VarietyCheckerUnitTest{
Mockery context = new JUnit4Mockery();
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void test_VarietyChecker() throws Exception{
final Apple mockapple = context.mock(Apple.class);
VarietyChecker printer = new VarietyChecker();
context.checking(new Expectations(){{
oneOf(mockapple).variety();will(returnValue("as"));
}});
String varietyNameValid = printer.printAppleVariety();
assertEquals("bad",varietyNameValid);
} }
This test fails - Mocking does not work the values "as" is not injected, the test class executes with MalgovaApple ...
Now if we add below constructor to VarietyChecker and use it test case - it gives expected output...
public VarietyChecker(Apple apple) {
super();
this.apple = apple;
}
and in unit test create test class object like
VarietyChecker printer = new VarietyChecker(mockapple);
Exposing a new constructor just for the purpose of testing is not a good idea. After all it is said that you should not alter the code for testing alone, more than that, i am afraid we have already written "some"(amount) code...
Am i missing something in junit or jmock that can make mocking work even incase of no-arg constructors. Or is this a limitation of simple junit and jmocks and should i migrate to something powerful like Jmockit /PowerMock
You should consider two choices.
Use a constructor parameter as you describe.
In this case, you're not "exposing a new constructor just for the purpose of testing". You're making your class more flexible by allowing callers to use a different factory implementation.
Don't mock it.
In this case, you are declaring that it never makes sense to use a different factory. Sometimes this is okay. At that point, the question changes, though. Instead of, "How do I mock this?" your question is now, "What am I gaining from writing this test?" You might not be gaining much of anything, and it might not make much sense to write the test at all.
If you don't mock it and decide a unit test is still worth it, then you should be asserting on other aspects of the code. Either an end state or some output. In this case, the factory call becomes an implementation detail that's not appropriate for mocking.
It's important not to fall for a "unit test everything" mentality. That is a recipe for Test-induced Design Damage. Evaluate your tests on a case by case basis, deciding whether they're providing you any real value or not. Not writing a unit test is a valid option and is even appropriate at times, even if it's option you try very hard to avoid.
Only you can make a determination which one makes the most sense in this case. From the the fact that this is a factory object we're talking about, I'd probably lean toward the former.
I ran into a problem with mockito.
I am developing a web application. In my tests the user management is mocked.
There are some cases when I have to alter the User returned by the getLoggedInUser() method.
The problem is, that my getLoggedInUser() method can also throw an AuthenticationException.
So when I try to switch from no user to some user, the call to
when(userProvider.getLoggedInUser()).thenReturn(user);
throws an exception, as userProvider.getLoggedInUser() is already stubbed with thenTrow()
Is there any way for to tell the when method not to care about exceptions?
Thanks in advance - István
In new Mockito versions you can use stubbing consecutive calls to throw exception on first can and returning a value on a second call.
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#10
My first reaction to your question is that it sounds like you are trying to do too much in one test.
For ease of testing and simplicity each test should test one thing only. This is the same as the Single Responsibility Principle. I often find programmers trying to test multiple things in one test and having all sorts of problems because of it. So each of your unit test methods should follow this flow:
Setup a single scenario for the test.
Make a call to the class being tested to trigger the code being tested.
Verify the behaviour.
So in your case I would expect to see at least two tests. One where getLoggedInUser() returns a user, and one where getLoggedInUser() throws an exception. That way you will not have problems with trying to simulate different behaviour in the mock.
The second thought that spring to mind is not to stub. Look into using expect instead because you can setup a series of expectation. I.e. the first call returns a user, the second call throws an exception, the third call returns a different user, etc.
Is there any way for to tell the when method not to care about exceptions?
To actually answer this question:
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;
import org.junit.Test;
import org.mockito.Mockito;
import java.util.ArrayList;
public class MyTest {
#Test
public void testA() {
// setup
ArrayList<Object> list = mock(ObjectArrayList.class);
when(list.indexOf(any())).thenReturn(6);
when(list.indexOf(any())).thenReturn(12);
// execute
int index = list.indexOf(new Object());
// verify
assertThat(index, is(equalTo(12)));
}
#Test
public void testB() {
// setup
ArrayList<Object> list = mock(ObjectArrayList.class);
when(list.add(any())).thenThrow(new AssertionError("can't get rid of me!"));
when(list.add(any())).thenReturn(true);
// execute
list.add(new Object());
}
#Test
public void testC() {
// setup
ArrayList<Object> list = mock(ObjectArrayList.class);
when(list.add(any())).thenThrow(new AssertionError("can't get rid of me!"));
Mockito.reset(list);
when(list.add(any())).thenReturn(true);
// execute
list.add(new Object());
}
/**
* Exists to work around the fact that mocking an ArrayList<Object>
* requires a cast, which causes "unchecked" warnings, that can only be suppressed...
*/
class ObjectArrayList extends ArrayList<Object> {
}
}
TestB fails due to the assert that you can't get rid of. TestC shows how the reset method can be used to reset the mock and remove the thenThrow command on it.
Note that reset doesn't always seem to work in some more complicated examples I have. I suspect it might be because they're using PowerMockito.mock rather than Mockito.mock?
Use Mockito.reset() to reset any particular mocks, for example Mockito.reset(mock1, mock2)
Check for more detail: https://stackoverflow.com/a/68126634/12085680
For example:
#Test
void test() {
when(mock.someMethod(any())).thenThrow(SomeException.class);
// Using a service that uses the mock inside for example
assertThrows(SomeException.class, () -> service.someMethodThatUsesTheMock("test"));
Mockito.reset(mock); // reset it so you can reuse that mock on another test
}