Can we mock third party object creation or calls? - java

For example I have the following handler:
#Component
public class MyHandler {
#AutoWired
private MyDependency myDependency;
public void someMethod(Object parameter) {
...
ThirdPartyClass thirdPartyObject = new ThirdPartyClass(parameter);
thirdPartyObject.unnecessaryMethod();
...
}
}
To test this, I want to write something like this:
#RunWith(MockitoJUnitRunner.class}
class MyHandlerTest {
#InjectMocks
MyHandler myHandler;
#Mock
MyDependency myDependency;
#Test
public void testSomeMethod() {
...
myHandler.someMethor(parameter);
...
}
}
I want to avoid calling unnecessaryMethod(). Is there any way to do this?
If unnecessaryMethod() is static then I can use PowerMockito to mock it, but can PowerMockito help in my situation?

I have found an answer:
public class MyHandler {
public void someMethod() {
Utils utils = new Utils(10);
System.out.println("Should be 1 : " + utils.someMethod());
}
}
Some Utils class:
public class Utils {
private int value = 5;
Utils () {
System.out.println("Should be mocked");
}
Utils (int param) {
this.value = param;
System.out.println("Should be mocked");
}
public int someMethod() {
System.out.println("Should be mocked");
return value;
}
}
And test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyHandler.class)
public class MyHandlerTest {
#InjectMocks
MyHandler myHandler;
#Test
public void testMain() throws Exception {
Utils utils = mock(Utils.class);
when(utils.someMethod()).thenReturn(1);
whenNew(Utils.class).withArguments(anyInt()).thenReturn(utils);
myHandler.someMethod();
}
}
Console output will be:
Should be 1 : 1
Related question

Related

Mocking constructor using PowerMockito doesn't work

I want to test a method which creates an object of another class using it's parameterized constructor. Even though I've mocked the constructor of MyClass, it makes the third party library which is in constructor implementation and results in the error. I'm using Mockito/PowerMockito.
public class MyClass{
private MyObj obj;
MyClass (String profile)
{
//some 3rd party library call
obj = thridPartyLib.someMethod(profile);
}
public String someMethod(){
return obj.someExternalCall();
}
}
Class which I want to test
public class ClassTobeTested{
public void execute(){
//some code
// ......
MyClass myClass = new MyClass(profile);
myclass.someMethod();
}
}
What I tried so far - classUnderTest.execute() ends up calling the thridPartyLib.someMethod(profile); which is part of MyClass constructor.
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = new ClassTobeTested();
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute(){
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
Your code will work only if you are working with a spy or mock of classUnderTest. Try this. This should work
#RunWith(PowerMockRunner.class)
#PrepareForTest( {MyClass.class, ClassTobeTested.class })
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = spy(new ClassTobeTested());
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute() throws Exception {
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
The pain might suggest another approach. Consider injecting a Factory into ClassTobeTested which knows how to create an instance of MyObj. For example:
class MyObjFactory {
MyObj create(String profile) {
return new MyClass(profile);
}
}
then
public class ClassTobeTested {
private final MyObjFactory factory;
public ClassTobeTested(MyObjFactory factory) {
this.factory = factory;
}
public void execute(){
//some code
// ......
// MyClass myClass = new MyClass(profile);
MyClass myClass = factory.create(profile);
myclass.someMethod();
}
}
so the unit test becomes simpler with only having to mock the Factory and have it return a mocked MyClass instance. Then it's simple to verify myclass.someMethod() was invoked as expected.

Test class which depends on Guice Provider<T>

How to test a class which depends on Provider<>?
Please see the code below.
class ToTest {
#Inject
Provider<Processor> processorProvider;
public buildData() {
processorProvider.get().process();
}
class ProcessorProviderImpl implements Provider<Processor> {
#Inject
private Handler someHandler;
public Processor get() {
return new MyProcessor(somehandler)
}
}
public static class TestModule extends JukitoModule {
#Override
protected void configureTest() {
bind(Processor.class).toProvider(
ProcessorInstanceProviderImpl.class);
bindMock(SubHandler.class).in(TestSingleton.class);
}
}
class Handler {
#Inject
private SubHandler subHandler; // this is singleton instance
}
}
So when I mock subHandler it doesn't work and when I run unit test I am getting a NullPointerException where subHandler.handle() is getting called.
You can use Providers.of() to initialize processorProvider with a provider of your collaborator instance.
https://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/util/Providers.html
test = new ToTest();
test.processorProvider = Providers.of(processorMock);

Powermock and Mockito. Avoid static initialization for a class while mocking and stubing the same class

Suppose I have a class named Util with static fields:
public class Util {
public static field = Param.getValue("param1");
}
and the class Param look like this:
public class Param {
public static field = SomeClass.getValue("someValue");
}
I want to mock and stubb Param.getValue("param1") inside Util, but at the same time I want suppress static initialization for Param class. How can I achieve this?
This is my first attempt but it's not working
#RunWith(PowerMockRunner.class)
#PrepareForTest({Param.class})
#SuppressStaticInitializationFor("py.com.company.Param")
public class Test {
#Test
public void testSomeMethod() {
PowerMockito.mockStatic(Param.class);
when(Param.getValue("value1")).thenReturn("someValue1");
}
}
This is working for me. I get no output, and SomeClass#getValue if no #SuppressStaticInitializationFor:
#RunWith(PowerMockRunner.class)
#SuppressStaticInitializationFor({"so35047166.Param"})
#PrepareForTest({Param.class})
public class UtilTest {
#Before
public void setUp() throws Exception {
PowerMockito.mockStatic(Param.class);
}
#Test
public void testFoo() throws Exception {
final Util util = new Util();
assertEquals("Util#foo", util.foo());
assertEquals(null, Util.field);
}
}
with:
// all in package so35047166;
public class Util {
public static String field = Param.getValue("param1");
public String foo() {
return "Util#foo";
}
}
public class Param {
public static String field = SomeClass.getValue("someValue");
public static String getValue(final String in) {
System.out.println("Param#getValue");
return "Param#getValue";
}
}
public class SomeClass {
public static String getValue(final String in) {
System.out.println("SomeClass#getValue");
return "SomeClass#getValue";
}
}

Test concrete method of an abstract class containing an interface call

I have a class:
public abstract class Foo{
#Inject
private FooBarClient foobarclient;
public abstract long dofoo1();
public abstract long dofoo2();
public void doBar1(){
foobarClient.docall(faa);
}
}
I'd like to test the doBar1() method so I made my test class like this:
#RunWith(MockitoJUnitRunner.class)
public class FooTest {
private Foo foo;
#Mock
private FoobarClient foobarClient;
#Before
public void init() {
foo = new Foo() {
dofoo1(){};
};
}
#Test
public void testControleValiditeSite() throws Exception {
// G
Response response=....;
Mockito.when(foobarClient.docall(Mockito.any(faa.class))).thenReturn(
response);
// W
foo.doBar1();
// T;
}
But I got a null pointer exception on the fooBarclient in doBar1().
I also tried to mock the abstract with:
Foo foo = Mockito.mock(Foo,Mockito.CALLS_REAL_METHODS);
Is there a better method to do this test?
EDIT :
I used reflection. Now the code looks like:
#RunWith(MockitoJUnitRunner.class)
public class FooTest {
private Foo foo;
#Mock
private FoobarClient mockedFoobarClient;
#Before
public void init() {
foo = new Foo() {
dofoo1(){};
};
**MockitoAnnotations.initMocks(this);**
**ReflectionTestUtils.setField(foo , "foobarClient", mockedFoobarClient);**
}
#Test
public void testControleValiditeSite() throws Exception {
// G
Response response=....;
Mockito.when(foobarClient.docall(Mockito.any(faa.class))).thenReturn(
response);
// W
foo.doBar1();
// T;
}
You might not need to mock it, just create an instance in your test (assuming you're able to change the access type of client from private to protected).
Foo foo = new Foo() {
#Override
public long dofoo1() {
return 0;
}
#Override
public long dofoo2() {
return 0;
}
public void setClient(FooBarClient client) {
foobarclient = client;
}
};
foo.setClient(client);
foo.doBar1();
In your test class, create a non-abstract inner class that extends Foo. Use that in your test.

Inject Mocks for objects created by Factory classes

I have the following class:
public class MyClass {
private Apple apple;
public void myMethod() {
apple = AppleFactory.createInstance(someStringVariable);
....
....
....
}
}
And the Test class:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#InjectMocks
MyClass myClass;
#Test
public void myMethod(){
...
...
...
}
}
How could I inject an Apple instance as a mock in MyClass?
You have 3 possibilities to solve this:
Abstract factory: Instead of using a static method, use a concrete factory class:
public abstract class AppleFactory {
public Apple createInstance(final String str);
}
public class AppleFactoryImpl implements AppleFactory {
public Apple createInstance(final String str) { // Implementation }
}
In your test class, mock the factory:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock
private AppleFactory appleFactoryMock;
#Mock
private Apple appleMock;
#InjectMocks
MyClass myClass;
#Before
public void setup() {
when(appleFactoryMock.createInstance(Matchers.anyString()).thenReturn(appleMock);
}
#Test
public void myMethod(){
...
...
...
}
}
PowerMock: Use PowerMock to create a mock of a static method. Look at my answer to a relevant question to see how it's done.
Testable class: Make the Apple creation wrapped in a protected method and create a test class that overrides it:
public class MyClass {
private Apple apple;
public void myMethod() {
apple = createApple();
....
....
....
}
protected Apple createApple() {
return AppleFactory.createInstance(someStringVariable);
}
}
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock
private Apple appleMock;
#InjectMocks
MyClass myClass;
#Test
public void myMethod(){
...
...
...
}
private class TestableMyClass extends MyClass {
#Override
public void createApple() {
return appleMock;
}
}
}
Of course, in your test class you should test TestableMyClass and not MyClass.
I'll tell you my opinion on each of the methods:
The abstract factory method is the best one - This is a clear design that hides the implementation details
The testable class - Is the second option which requires minimum changes
The PowerMock option is my least favorite - Instead of going for a better design, you ignore and hide your problem. But that's still a valid option.
In addition of the solution proposed by Avi, you can choose a fourth possibility:
Inject into Factory:
This is, for me, the best option when you already have code to refacrot. With this solution you don't have to change porduction code but only factory class and test.
public class AppleFactory
{
private static Apple _injectedApple;
public static createInstance(String str)
{
if (_injectedApple != null)
{
var currentApple = _injectedApple;
_injectedApple = null;
return currentApple;
}
//standard implementation
}
public static setInjectedApple(Apple apple)
{
_injectedApple = apple;
}
}
Now you can use your static factory simply:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock
private Apple appleMock;
#InjectMocks
MyClass myClass;
#Before
public void setup() {
AppleFactory.setInjectedApple(appleMock);
}
#Test
public void myMethod(){
...
...
...
}
}

Categories