ReflectionTestUtils set field method - java

Is there a way to use ReflectionTestUtils to set the return value of a method inside a field that represents a class to a mocked value instead of mocking the entire field? I was trying .setField(), but that only seems to work for the entire field. If there isn't, what would be a good substitute? Example of what I mean below:
public class Example() {
private ClassField field;
public methodThatUsesField() {
methodReturnType type = field.method(); // I was trying to call .setField() to change the field's method to a mocked value, but can't figure out how to do it
...
}
}
The class that is called in the field is very complicated, but there is a very simple public method that acts as the root of the class, and I want to set that to a specific value. The class itself does not have a constructor, so I need a way to get around that.
This is a spring boot project written in Java, and I need to use ReflectionTestUtils to be able to pass an argument into Mockito mock

You can use Mockito.spy(field) and inject spied field using ReflectionTestUtils. Something like this
#SpringBootTest
class ExampleTest {
#Autowired
private Example example;
#Autowired
private ClassField field;
#Test
void testMethodThatUsesField() {
ClassField spiedField = Mockito.spy(field);
Mockito.when(spiedField.method()).thenReturn(methodReturnTypeValue);
ReflectionTestUtils.setField(example, "field", spiedField);
example.methodThatUsesField();
// assertions
}
}

Related

How to cover the Class instantiated inside a method in Mockito Junit?

How can I cover the class instantiated inside a method and need to get the value that is not set.
Here is my Service class DemoClass.Java
public class DemoClass{
public void methodOne(){
ClassTwo classTwo=new ClassTwo();
classTwo.setName("abc");
customerRepo.save(classTwo);
ClassThree classThree=new ClassThree();
classThree.setId(classTwo.getId()); //here causing NullPointerException as ClassTwo is instantiated inside the method and the id value is not set and the test stops here.
classThree.setName("person1");
classThree.setUpdatedBy("person2");
}
}
As the classTwo is instantiated in the method level the test method does not get the getId(). And I can't change or add anything to the Controller class. The test stops at that line and causing NullPointerException as it doesn't know the value classtwo.getId() as it is not set. I need to cover that/ pass that line in the test class.
I tried mocking that class and spy also. Any Mockito solutions available for this.
The Id in ClassTwo is an autogenerated sequence number so no need of setting in DemoClass.Java
Here is my test class DemoClassTest.Java
#RunWith(MockitoJunitRunner.Silent.class)
public void DemoClassTest(){
#InjectMocks
DemoClass demoClass;
#Test
public void testMethodOne(){
demoClass.methodOne()
}
You could provide a customerRepo test double that just sets some specific id on classTwo:
public class TestCustomerRepo extends CustomerRepo {
public void save(ClassTwo classTwo) {
classTwo.setId(4711L);
}
}
But since you seem to be testing JPA code it would probably be a better idea to perform an integration test containing an actual database instead.
I usually do it like this:
long testId = 123;
Mockito.when(customerRepo.save(Mockito.any())).thenAnswer(invocation -> {
ClassTwo entity = (ClassTwo)invocation.getArgument(0);
entity.setId(testId);
return entity;
});
If you want to assert something on the ClassThree entity, do a Mockito.verify on the ClassThree repository mock.

Mocking public method inside a private method

I have a class like below:
public class ClassOne {
public function1(input, output, context) {
//some implementation
private function2(List, String, String);
}
private void function2(List, String, String){
Class2 class2 = new Class2();
String value = class2.method1(string, string);
}
}
public Class2 {
public String method2(string, string) {
//some implementation
return string;
}
}
I am writing Unit test for ClassOne using Mockito and PowerMockito and would like to mock the call to class2 and do not want to actually call method body for method2. How can I achieve this?
I tried Mockito.mock and PowerMockito.spy the class and when(class2.method2).thenReturn() and doReturn().when(class2).method2(); but everything calls the method body when I do classOne.function1. I have spied the ClassOne.
It would be really helpful if you would have also provided your non working Unit Tests. On the other hand I'm pretty sure the problem isn't there anyway :)
Your problem is not that Mockito & PowerMockito are not working.
The real problem is in the dependency of you classes. Or to be more specific the way your classes handle this dependency.
In General it is not a good idea to instantiate the dependency (Class2) in the place it is needed (ClassOne). As you can see right now it makes testing pretty hard.
It would be better to pass the dependency into the class that needs it.
This is called Dependency Injection (DI).
In your example you would pass an object of Class2 into the constructor of ClassOne. The Code would look something like that:
public class ClassOne {
private final Class2 class2;
public ClassOne(Class2 class2) {
this.class2 = class2;
}
...
private void function2(List, String, String){
String value = class2.method1(string, string);
}
}
As you can see you simply pass an instance of your dependency and use this one instead of creating it on your own.
In your Unit Test you are now able to pass a Mock of Class2 into your Class1 object which will then be used.

how to inject a dependency in a java enum?

I am trying to inject a bean into an enum but i keep getting null pointer exception when call to someMethod is made.
The answer mentioned in this Inject bean into enum worked for me. I want to know why my code didn't work
#Component
public class DataProvider {
public int method1() {
//somecode
}
}
public enum Genres {
DRAMA(1,”Drama”);
ADVENTURE(2,”Adventure”);
HORROR(3,”Horror”);
private int id;
private String name;
#Inject DataProvider dataprovider;
public int someMethod() {
return dataprovider.method1();
}
}
What the answer you linked does is loop the enum values and use a setter to inject the DataProvider dependency
public void postConstruct() {
for (ReportType rt : EnumSet.allOf(ReportType.class)) {
rt.setDataPrepareService(dataPrepareService);
}
}
It works because the ReportTypeServiceInjector class is an inner, static class, and so it can be seen and instantiated by Spring.
It's a crazy design anyway. Avoid it.
Ultimately, keep the enum simple and extract the DataProvider usage.
Your original code didn't work because Spring cannot #Autowire/#Inject dependencies in enums.
Generally, it is not a good practice to have dependency injection in enums as they are designed to be constants/static (Reference)
But, I agree with you, many times, we need to associate some real time behavior to be encapsulated along with Enum values.
I would suggest, create a new class and encapsulate Enum within that.
class GenresService{
// 1st option: Declare Genres enum reference at class level and
// initialize using class constructor/injection.
// Genres g;
#Inject DataProvider dataprovider;
//2nd option: pass Genres value to method at real time.
public int someMethod(Genres g) {
return dataprovider.method1();
}
}
To have any injection to work you would need to have your enum also managed. You could try to inject your enum but how and what would you inject? It presents constant values and in addition it has private no args constructor.
So the way you might have it working would be some JNDI lookup - that initializes dataProvider - inside your someMethod() or using some static context accessor.
And: for for Spring it is not #Inject but #Resource or #Autowired

Test if another method was called

So I'm sure there is something like this out there but I have been searching for an hour and haven't found exactly what I am looking for. say I have a class that looks like this:
public class MyClass
{
public void myMethod(boolean shouldCallOtherMethod)
{
if(shouldCallOtherMethod)
{
otherMethod();
}
}
public void otherMethod()
{
System.out.println("Called");
}
}
How do I make something like this work?
#Test
public void shouldCallMethod()
{
MyClass myClass = new MyClass();
myClass.myMethod(true)
// verify myClass.otherMethod method was called
}
Using Mockito, you can do spying on real objects like this:
import org.junit.Test;
import static org.mockito.Mockito.*;
public class MyClassTest {
#Test
public void otherMethodShouldBeCalled() {
MyClass myClass = new MyClass();
MyClass spy = spy(myClass);
spy.myMethod(true);
verify(spy).otherMethod();
}
}
There are some gotchas, so take a look at the relevant documentation as well.
Suppose MokeysClass has a constructor declared like this, where Foo is some other class.
public MokeysClass(String name, int counter, Foo myFoo)
I would write my test like this.
#RunWith(MockitoJUnitRunner.class)
public class TestArray {
#Mock
private Foo mockMyFoo;
private String nameToInject = "Mokey";
private int counterToInject = 42;
#Spy
private MokeysClass toTest = new MokeysClass(nameToInject, counterToInject, mockMyFoo);
#Test
public void shouldCallMethod() {
toTest.myMethod(true);
verify(toTest).otherMethod();
}
}
so that I am explicitly stating which constructor to call when I create my test object, and what arguments to pass to it.
There are some reasons not to rely on #InjectMocks to do this step for me, particularly if the class being tested is more complex and has more than one constructor. Mockito chooses the constructor that has the most arguments, but if there are several constructors with the same number of arguments, Mockito could choose any of the constructors; that is, the behaviour is undefined.
Once Mockito has chosen a constructor, it checks whether that constructor can in fact be used for constructor injection. Constructor injection will not be used if
one or more of the parameters of the chosen constructor is a primitive type,
the type of one or more of the parameters of the chosen constructor is a final class,
the type of one or more of the parameters of the chosen constructor is a private class,
the only constructor of the class is the default constructor.
If any one of these conditions holds, for the constructor that Mockito chose, then constructor injection won’t be used. In this case, the class must have a default constructor, otherwise Mockito will throw an exception.
The complexity of the criteria which Mockito uses when choosing whether to apply constructor injection implies that adding or removing a constructor, or changing the parameters of a constructor, can make Mockito switch from using constructor injection to using setter and field injection; or from using setter and field injection to using constructor injection. This can occur even if the constructor that is changed is not the one that will be used for constructor injection.
As a result, any test that uses constructor injection is automatically quite brittle; in the sense that changes that are not directly related to the test itself can cause the test to fail. Such failures can be difficult to troubleshoot.
The #InjectMocks annotation was designed for use with frameworks such as Spring that do dependency injection; and for tests of classes that use Spring, it can be invaluable. But if dependency injection is not part of your class, I would strongly recommend avoiding #InjectMocks on account of its brittleness. You really want your test code to be as easy to maintain and to troubleshoot as your production code is.
This is not recommended, but you can spy real object :)
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.BDDMockito.verify;
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Spy
private MyClass sut; // System Under Test
#Test
public void shouldCallMethod() {
// when
sut.myMethod(true);
// then
verify(sut).otherMethod();
}
}
Result:
Tests Passed: 1 passed in 0,203 s
After changing code: sut.myMethod(false);
Wanted but not invoked:
sut.otherMethod();
-> at my.custom.MyClassTest.shouldCallMethod(MyClassTest.java:23)
Source: Spying on real objects
Magic version with constructor injection
#Mock
private LexAnalyzer lexAnalyzer;
#Spy
#InjectMocks
private SyntaxAnalyzer sut; // System Under Test
#Test
public void shouldCallMethod() {
// when
sut.myMethod(true);
// then
verify(sut).otherMethod();
}
SyntaxAnalyzer.java
public class SyntaxAnalyzer {
private final LexAnalyzer lexAnalyzer;
public SyntaxAnalyzer(LexAnalyzer lexAnalyzer) {
this.lexAnalyzer = lexAnalyzer;
}
...
Tested, works ;)
I think you want to look at Mock objects. You can create a mock of MyClass, then set expectations that otherMethod() is called when you call myMethod and fails if it was not called.
Here is a pretty good overview of them for java - http://www.scalatest.org/user_guide/testing_with_mock_objects
One other major benefit of using Mocks, you can avoid side affects, like logging to NSLog or hitting a web server or printing) in your test.

How to avoid actual method call while running through junit test case

I have the following scenario.
A class MyClass in which I have an API myAPI() whose contents are as follows:
class MyClass {
public void myAPI() {
...
MyOtherClass myOtherObj = new MyOtherClass();
String value = myOtherObj.decodeAndGetName();
...
}
}
Here we have MyOtherClass which contains an API decodeAndGetName() which does some operation. It is in a different package and I can't modify its code.
Requirement
I need to write a junit test for the above myAPI(). Now I want to somehow mock the object of MyOtherClass and mock the return value of decodeAndGetName().
I am not able to do this, as we have a new MyOtherClass() and as soon as the flow comes to this line, it creates a new instance and goes to the decodeAndGetName() API.
What I need is, some way to prevent the flow going to decodeAndGetName() and take a mock value instead when this call is encountered in the above code.
Please let me know a way to do this.
I've only used it with Android code, but I think you may be able to make use of something like Mockito to mock the MyOtherClass in your tests with code similar to:
MyOtherClass mockMyOtherClass = Mockito.mock(MyOtherClass.class);
when(mockMyOtherClass.decodeAndGetName()).thenReturn(new String("known return value");
I would also suggest using dependency injection and make use of something like Guice in order to accomplish this. I use the combination of Guice & Mockito on a daily basis with my Android projects to successfully accomplish exactly this sort of thing.
Brief Example
Here is what your code may look like after setting up dependency injection with Guice:
MyOtherClassWrapper.java
#Singleton
public class MyOtherClassWrapper {
private MyOtherClass myOtherClass = new MyOtherClass();
public String decodeAndGetName() {
return getMyOtherClass().decodeAndGetName();
}
...
private MyOtherClass getMyOtherClass() {
return myOtherClass;
}
}
MyClass.java
class MyClass {
...
#Inject private MyOtherClassWrapper myOtherClassWrapper;
...
public void myAPI() {
...
String value = getMyOtherClassWrapper().decodeAndGetName();
...
}
private MyOtherClass getMyOtherClassWrapper() {
return myOtherClassWrapper;
}
}
Please see the Guice User's Guide for info on how to get started setting up Guice. It's not too difficult.

Categories