I have a class that I mocked like this:
#Mock
private MyClass1 mockMyClass1;
Say this class looks like that:
public class MyClass1 {
#Autowired
private MyInnerClass myInnerClass;
}
When I mock MyClass1, MyInnerClass will be initialized as null. Is it possible to initialize that private field with another mock objected? I want myInnerClass to be a mock like this one:
#Mock
private MyInnerClass myInnerClass;
If I use the following code:
#InjectMocks
private MyClass1 mockMyClass1;
#Mock
private MyInnerClass myInnerClass
This will initialize the private MyInnerClass inside MyClass1 to be the mocked object, however this way mockMyClass1 is not a mock itself any more, isn't it (I'm only injecting a mocked object inside a real class, just like #Autowired will inject a real object insite it)? Could you correct my logic if I'm wrong in my understanding of #InjectMock and #Mock? Also how could I inject a mocked object inside another mocked object (without using setters/constructors)?
You are misunderstanding what a mock is.
When you are mocking MyClass1, the inner field of type MyInnerClass doesn't exist anymore for the mocked object. As such, it doesn't make sense to try to inject something into a mock.
A mock is controlled by saying what it should do when you interact with it. You stub its public methods to do what you want them to do. You give behaviour. The only default behaviour (maybe specific to Mockito) is to return null if you didn't configure the mock (but do note that it doesn't return null because some internal variable is null, it returns that because Mockito decided that that's what it should return; maybe another mocking framework decided that it should throw an exception instead, who knows?).
As an example, consider that your real class is:
class MyClass1 {
private MyInnerClass myInnerClass;
public MyInnerClass getMyInnerClass() {
return myInnerClass;
}
}
Now consider mock a mock of that class. If you call mock.getMyInnerClass(), it is not the real method that is going to be called. What it will return is not the value of myInnerClass. It will return null, or if you have stubbed that method with
when(mock.getMyInnerClass()).thenReturn(something);
then it will return something.
So to answer your question: you can't do that because that's not how mocks work.
You shouldn't really use InjectMocks annotation at all (to see why, you can read this article).
You could just implement an Autowired constructor for MyClass1 instead of Autowired fields. Then you could simply pass your MyInnerClass mock reference as a constructor parameter.
Related
In Kotlin, a variable must be initialized at declaration time, and cannot be null unless it has ? appended to the type name. So a bean reference intended to be injected by Spring would have to be declared as:
#AutoWired
var someService: SomeService? = null
The nuisance is obviously that from here on everywhere someService is used, some kind of null-safety logic has to be specified, be it ?: or a straight-up null check.
Of course we can do:
#AutoWired
var someService = new SomeService()
But that's not always possible, and the throwaway instance is just confusing.
My question is, is there anyway to tell Kotlin that this variable will be initialized and actually not be null?
You have two options.
1) use constructor injection
Constructor injection is in my opinion the best way because it clearly declares that the dependencies must be set to construct the object.
2) declare your field as lateinit
Read more on tht topic in the doc:
https://kotlinlang.org/docs/reference/properties.html
Late-Initialized Properties
Normally, properties declared as having a non-null type must be
initialized in the constructor. However, fairly often this is not
convenient. For example, properties can be initialized through
dependency injection, or in the setup method of a unit test. In this
case, you cannot supply a non-null initializer in the constructor, but
you still want to avoid null checks when referencing the property
inside the body of a class.
public class MyTest {
lateinit var subject: TestSubject
#SetUp fun setup() {
subject = TestSubject()
}
#Test fun test() {
subject.method() // dereference directly
}
}
The Spring project official recommendation is to use constructor injection.
In Kotlin it will look something like this:
#Service
class GobblinMetricsConsumer(
private val graphiteClient: GraphiteClient,
private val parserService: JsonParserService,
private val kafkaConfigurationProperties: KafkaConfigurationProperties
) {
// code will go here
}
I have this test:
#RunWith(MockitoJUnitRunner.class)
public class MainClassTest {
#Mock
Dependence dependence;
#InjectMocks
MainClass mainClassTester;
}
And this test:
#Test
public void testA() {
when(dependence.getStatus()).thenReturn(true);
mainClassTester.startStatusOperation();
}
My MainClass class looks like:
public class MainClass{
private Dependence dependence = new Dependence() ;
public boolean startStatusOperation(){
boolean status = dependence.getStatus();
[...]
}
}
Im getting NullPointer in this line:
boolean status = dependence.getStatus();
Why doesn't the mock "dependence" work? This code always worked when I used #inject, but can't use in this one.
If you want to use constructor to create object instead of #Inject, you need to mock the constructor instead of just using #Mock.
#InjectMock will only inject the field which you use by #Inject. If you have any field which is set by new constructor, this will be not injected in test object if you use #InjectMock.
From http://site.mockito.org/mockito/docs/current/org/mockito/InjectMocks.html
#Documented
#Target(value=FIELD)
#Retention(value=RUNTIME)
public #interface InjectMocks
Mark a field on which injection should be performed.
Allows shorthand mock and spy injection.
Minimizes repetitive mock and spy injection.
Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below. If any of the following strategy fail, then Mockito won't report failure; i.e. you will have to provide dependencies yourself.
Constructor injection; the biggest constructor is chosen, then arguments are resolved with mocks declared in the test only. If the object is successfully created with the constructor, then Mockito won't try the other strategies. Mockito has decided to no corrupt an object if it has a parametered constructor.
Note: If arguments can not be found, then null is passed. If non-mockable types are wanted, then constructor injection won't happen. In these cases, you will have to satisfy dependencies yourself.
Property setter injection; mocks will first be resolved by type (if a single type match injection will happen regardless of the name), then, if there is several property of the same type, by the match of the property name and the mock name.
Note 1: If you have properties with the same type (or same erasure), it's better to name all #Mock annotated fields with the matching properties, otherwise Mockito might get confused and injection won't happen.
Note 2: If #InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.
Field injection; mocks will first be resolved by type (if a single type match injection will happen regardless of the name), then, if there is several property of the same type, by the match of the field name and the mock name.
Note 1: If you have fields with the same type (or same erasure), it's better to name all #Mock annotated fields with the matching fields, otherwise Mockito might get confused and injection won't happen.
Note 2: If #InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.
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.
I am new to Spring and JUnit. I need to mock a class which is derived from ApplicationContextAware class which is inside my toBeTested(getList) method. In the following short code snippet, I need to test the getList method in abc class.
I am able to mock ModulesConfigRegistry because there is a setter for it. But I am not able to mock ModuleConfig and ListProvider. Both ModulesConfigRegistry and ModuleConfig have implemented ApplicationContextAware so it returns classes from bean. ListProvider.getList(lst.getList in code) is the method which makes further calls up to database and is required to be mocked. Appreciate your help in advance. Code sample will be helpful as I am new to Spring and JUnit.
class abc {
private ModulesConfigRegistry modulesConfigRegistry;
public void setModulesConfigRegistry(ModulesConfigRegistry modulesConfigRegistry) {
this.modulesConfigRegistry = modulesConfigRegistry;
}
public List getList(String name, String moduleName)
{
ModuleConfig moduleConfig = modulesConfigRegistry.getModuleConfig(moduleName);
Object mlist = moduleConfig.getListProvider(name);
if(mlist instanceof ListProvider)
{
ListProvider lst = (ListProvider)mList;
}
return lst.getList("abc");
}
}
Maybe there is another more simple way to achieve this (not mandatory the best). In my experience I've used Reflection in Java when it's up to Unit-testing. After all, to me the main purpose of the unit tests is to simply exercise smallest testable part and nothing more. That's why I simply use my dummy-test-object and get/set fields/properties I need.
But one thing that must be considered here is that reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects. So if you know what your doing it's a good alternative.
Since you already using
JUnit
One very common use case in Java is the usage with annotations. JUnit 4, for example, will use reflection to look through your classes for methods tagged with the #Test annotation, and will then call them when running the unit test.
If you want to consider it and use it - here you can find some good examples.
Cheers.
One approach here is create mock objects for each object that you need to interact with ModuleConfig and ListProvider
#RunWith(MockitoJUnitRunner.class)
public class abcTest{
#InjectMocks
private abc abcInstance;
#Mock
private ModulesConfigRegistry modulesConfigRegistry ;
#Test
private voidTestGetList(){
//Create the mock and interactions
ModuleConfig moduleConfigMock = Mockito.mock(ModuleConfig.class);
ListProvider listProviderMock = Mockito.mock(ListProvider.class);
ArrayList listToReturn = new ArrayList();
Mockito.when(modulesConfigRegistry.getModuleConfig(Mockito.anyString())).thenReturn(moduleConfigMock);
Mockito.when(moduleConfigMock.getListProvider(Mockito.anyString())).thenReturn(listProviderMock);
Mockito.when(listProviderMock.getList(Mockito.anyString())).thenReturn(listProviderMock);
//Call real method
List resultList = abcInstance.getList("stringInput1", "stringInput2");
//Make assertions
}
}
Basically you need to create mock objects for any of the instances that you get from a mock object and use mockito to define the result of its method.
Other options is create a new class that implements or is a subclass of the returned object type and override the methods.
I have a method that I have to write the junit for
public String getSomething(String no)
{
ThirdPartyClass.Innerclass innerclass = new ThirdPartyClass.Innerclass(..);
String result = innerClass.getSomething(no);
}
I know how to set the private fields in a class using the Whitebox. How can i mock the ThirdPartyClass and ThirdPartyClass.Innerclass
Two options here.
First and best is to not call new in the method. Pass in an InnerClass factory instance to the constructor of the class under test. Then mock this factory.
Second, use a mocking framework like Powermock which can intercept and mock constructor calls.
Mock Constructor