How to mock a global object in a class properly? - java

Let say I have a class like so
Class A{
private K Obj = (K)(AppContext.getSpringContext().getBean("obj"))
public void method1{
// uses Obj
}
public void method2{
// uses Obj
}
}
And I need to write junits for method1 and method2 by changing the behavior of Obj in method 1 and method 2. In my junit class I am setting the appcontext as so:
public class AccountInformationManagerTest {
private CCBSAppContext appContext;
#Mock
ApplicationContext springContext;
#Mock
Object obj;
#Before
public void setup() throws Exception {
appContext = new CCBSAppContext();
appContext.setApplicationContext(springContext);
Mockito.when(springContext.getBean("obj")).thenReturn(obj);
}
}
As you can see, I am setting globally the appcontext. I don't want mock the static calls as I am using jacoco and powermockito doesn't integrate very well with jacoco. The problem here is that appcontext is now a global object which is shared across all methods and I need to modify the behavior of obj as I test the two methods. This will create a concurrency issue. How can I resolve this?

TBH avoid (K)(AppContext.getSpringContext().getBean("obj")) directly inject dependency or autowire the dependency . Then in its easily testable and add obj to the class via SpringTestUtils or setters.
#Autowired
K obj;
Else you can mock springContext getBean method for every test
#Test
void fun {
Mockito.when(springContext.getBean(Mockito.eq("obj"))).thenReturn(obj);
// doSomething
}
#Test
void fun2 {
Mockito.when(springContext.getBean(Mockito.eq("obj"))).thenReturn(obj2);
// doSomething2
}

Use reflection to set the Obj. Then you can set Obj to be a mocked object.
Here is a SO answer describing how to do it.

Related

Mockito: Mock object which is no member but is created inline

I have a class which does the following:
public class Transformer {
public void transform(final Car car) throws IOException {
switch (car.getType()) {
case OFFROAD:
OffroadCar offroadCar = new OffroadTransformer().transform(car);
// do something with offorad car
break;
...
}
}
}
I have a test class:
public class TransformerTest {
#InjectMocks
private Transformer transformer;
#Mock
private OffroadTransformer offroadTransformer;
#BeforeEach
public void setup()
MockitoAnnotations.initMocks(this);
}
#Test
public void testTransform() throws IOException {
final Car car = new Car(OFFROAD);
when(offroadTransformer.transform(any(Car.class))).thenReturn(new OffroadCar());
transformer.transform(car);
// make some verifictations
}
}
My problem now is that the when is not working. The real offroadTransformer.transform is called instead of the mock. So my assumption is that the mock is not working because the OffroadTransformer is no member of the class Transformer and the instance is created inline.
Is that correct?
If yes: How can I anyway mock it?
If no: What else could be the cause?
The problem is that the OffroadTransformer object being used is not mocked. Your test setup is creating a mock in the transformer field, but this mock is not the one being used by the method, and that confirms your hypothesis.
The setup you're using works with classes that have mocked objects as instance fields, like this:
public class Transformer {
//injected, initialized inline, etc.
private OffroadTransformer transformer;
public void transform(final Car car) throws IOException {
switch (car.getType()) {
case OFFROAD:
OffroadCar offroadCar = this.transformer.transform(car);
// do something with offorad car
break;
...
}
}
}
Into such a class, Mockito would inject the mock and the method execution would use that mock created by Mockito.
If you do not want to use this set up, then you may want to look into something like mocking the constructor of your OffroadTransformer.
On a side note, however, it's rather common practice for factory classes such as OffroadTransformer to have no state and to be used as singletons. It's therefore more natural to follow the setup mentioned above and let Mockito handle the injection for you.

Mockito Spying on Class that has an internal method reference

I'm seeing a different in behaviour when spying on a service using the #Spy annotation and having Mockito create the Server verses explicitly calling the constructor.
public class MyService {
private final Supplier<String> methodBCall;
public MyService() {
methodBCall = this::methodB;
}
public void methodA() {
methodBCall.get();
}
public String methodB() {
return "methodB";
}
}
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Spy
private MyService myService1;
#Spy
private MyService myService2 = new MyService();
#Test
public void testSucceeds() {
myService1.methodA();
verify(myService1, times(1)).methodA();
verify(myService1, times(1)).methodB();
}
#Test
public void testFails() {
myService2.methodA();
verify(myService2, times(1)).methodA();
verify(myService2, times(1)).methodB();
}
}
The failing test fails with
Wanted but not invoked:
myService2.methodB();
-> at com.phemi.services.policy.impl.MyTest.testFails
Why do these two behave differently? What is Mockito doing to initialize myService1 that enables it to spy on methodB?
This is a simplified example, in my case to test my service properly I need to call its constructor with an argument (and so cannot use the #Spy with a default constructor). However, when I do that I cannot properly verify method calls.
The spy on myService2 is only created after the object has been constructed, so having a method call in the constructor is not helpfull as it contains a method reference to the initial object (which is not the spy object).
The difference becomes more evident when you compare the implementation for both cases:
Mockito.spy(Class)
public static <T> T spy(Class<T> classToSpy) {
return MOCKITO_CORE.mock(classToSpy, withSettings()
.useConstructor()
.defaultAnswer(CALLS_REAL_METHODS));
}
Mockito.spy(Object)
public static <T> T spy(T object) {
return MOCKITO_CORE.mock((Class<T>) object.getClass(), withSettings()
.spiedInstance(object)
.defaultAnswer(CALLS_REAL_METHODS));
}
As you can see the first case, based on a class (which is used if no instance for #Spy was created), creates a mock first and uses the constructor on the mocked object.
In the second case the constructor is not considered instead a different instance is created.

How can I test if a method was called on an object created inside the method to be tested

Is it possible to test that the "innerMethod" was called without modifying the Class class?
I need to make a unit test in a separate class both scenario of the "someCondition".
The problem is that the method is void so I cannot make use of the return type. The only way would be to check if the "innerMethod" was called.
I was thinking to use Mokito verify but this method is called inside a method on an object created at runtime.
Any suggestion is most welcome.
public class Class {
public void outerMethod(outerObj) {
if(someCondition) {
Object innerObj = new Object();
innerObj.innerMethod(outerObj);
} else {
//other code
}
}
You can achieve that with the use of Mockito::times and Mockito::verify methods.
test setup would be as follows:
#InjectMocks
private SomeService service;
#Mock
private SomeHelper helper;
and then test that some method from the helper has been involved in the following manner:
#Test
public void testInnerHasBeenCalledOnce() throws Exception {
service.outherMethodName(someParam);
Mockito.verify(helper, Mockito.times(1)).innerMethodName(someParamSecond);
}

Exception : mockito wanted but not invoked, Actually there were zero interactions with this mock

I have interface
Interface MyInterface {
myMethodToBeVerified (String, String);
}
And implementation of interface is
class MyClassToBeTested implements MyInterface {
myMethodToBeVerified(String, String) {
…….
}
}
I have another class
class MyClass {
MyInterface myObj = new MyClassToBeTested();
public void abc(){
myObj.myMethodToBeVerified (new String(“a”), new String(“b”));
}
}
I am trying to write JUnit for MyClass. I have done
class MyClassTest {
MyClass myClass = new MyClass();
#Mock
MyInterface myInterface;
testAbc(){
myClass.abc();
verify(myInterface).myMethodToBeVerified(new String(“a”), new String(“b”));
}
}
But I am getting mockito wanted but not invoked, Actually there were zero interactions with this mock at verify call.
can anyone suggest some solutions.
You need to inject mock inside the class you're testing. At the moment you're interacting with the real object, not with the mock one. You can fix the code in a following way:
void testAbc(){
myClass.myObj = myInteface;
myClass.abc();
verify(myInterface).myMethodToBeVerified(new String("a"), new String("b"));
}
although it would be a wiser choice to extract all initialization code into #Before
#Before
void setUp(){
myClass = new myClass();
myClass.myObj = myInteface;
}
#Test
void testAbc(){
myClass.abc();
verify(myInterface).myMethodToBeVerified(new String("a"), new String("b"));
}
Your class MyClass creates a new MyClassToBeTested, instead of using your mock. My article on the Mockito wiki describes two ways of dealing with this.
#Jk1's answer is fine, but Mockito also allows for more succinct injection using annotations:
#InjectMocks MyClass myClass; //#InjectMocks automatically instantiates too
#Mock MyInterface myInterface
But regardless of which method you use, the annotations are not being processed (not even your #Mock) unless you somehow call the static MockitoAnnotation.initMocks() or annotate the class with #RunWith(MockitoJUnitRunner.class).
#jk1 answer is perfect, since #igor Ganapolsky asked, why can't we use Mockito.mock here? i post this answer.
For that we have provide one setter method for myobj and set the myobj value with mocked object.
class MyClass {
MyInterface myObj;
public void abc() {
myObj.myMethodToBeVerified (new String("a"), new String("b"));
}
public void setMyObj(MyInterface obj)
{
this.myObj=obj;
}
}
In our Test class, we have to write below code
class MyClassTest {
MyClass myClass = new MyClass();
#Mock
MyInterface myInterface;
#test
testAbc() {
myclass.setMyObj(myInterface); //it is good to have in #before method
myClass.abc();
verify(myInterface).myMethodToBeVerified(new String("a"), new String("b"));
}
}
This exception can also be thrown if say, you expect thisMethod() to execute, but it didn't. It didn't because it's inside a condition that was not met.
For example, if you have some unit test that says verify thisMethod() is executed, but in fact, it was not because varX and varY are not equal.
//method expected to be called.
if( varX == varY){
thisMethod();
}
//test
Mockito.verify(foo).thisMethod();

JUnit mocking with Mockito, EasyMock, etc

I'm trying to mock a method of an object inside the class I'm testing.
For instance
class ClassToTest {
public doSomething () {
SomeObject a = new SomeObject ();
a.doSomethingElse ();
}
}
Is there a way to mock the methods of the variable "a"? I'd like doSomethingElse to do nothing during testing. I'm currently using Mockito but I'm open to any mocking framework.
Thanks
Yes, there is a way, as shown by the following JMockit test:
public void testDoSomething(final SomeObject mock)
{
new ClassToTest().doSomething();
new Verifications() {{ mock.doSomethingElse(); }};
}
No need to refactor code under test to use a wrapper, DI, etc; simply mock whatever you need to be mocked.
It's not possible to mock the reference "a" when it's declared as a local variable, as in your case. You could consider injecting the dependency to SomeObject, e.g. as a parameter of doSomething method. That way, you can inject a mock of SomeObject in your test instead.
One of the benefits of dependency injection is increased testability.
With some refactoring it is possible, of course:
class SomeObject {
public void doSomethingElse()
{
}
}
class ClassToTest
{
private final SomeObject someObject;
public void doSomething()
{
someObject.doSomethingElse();
}
public ClassToTest(SomeObject someObject)
{
this.someObject = someObject;
}
}
class Test {
#Test
public void testDoSomething()
{
SomeObject someObject = Mockito.mock(SomeObject.class);
new ClassToTest(someObject).doSomething();
Mockito.verify(someObject, Mockito.atLeastOnce()).doSomethingElse();
}
}
I believe you can use EasyMock Class Extensions for EasyMock 2.5 or earlier, and apparently it is included in 3.0. See this part of the previous page for information on what you are trying to do. That said, I haven't personally tried to do that, so I don't know how well it will work.
If you want a new instance in each call, I'd suggest refactoring in the following way:
class ClassToTest {
public doSomething () {
SomeObject a = getInstance();
a.doSomethingElse ();
}
protected SomeObject getInstance() {
return new SomeObject();
}
}
Then you can create a testclass extending ClassToTest, overriding the getInstance() method, with one supplying a mock object.
This is of course only viable if you are ok with exposing the getInstance() method, so I don't recommend it if the class is part of a public API. If this is the case, consider supplying a factory class using dependency injection.
class ClassToTest {
private SomethingElseInterface somethingElseDoer ;
public ClassToTest(SomethingElseInterface somethingElseDoer) {
this.somethingElseDoer = somethingElseDoer;
}
public doSomething () {
somethingElseDoer.doSomethingElse();
}
}
And where you use it:
SomethingElseInterface somethingElseDoer = ...; // in a test, this is where you mock it
ClassToTest foo = new ClassToTest(somethingElseDoer); // inject through constructor
foo.doSomething();

Categories

Resources