public Data extraMethod(Data data) // interface Data
{
Data d = Singleton.getInstance().sort(data.get() , "desc");
//do something, logical
return d;
}
How can I mock the object Data(the singleton extra return result), class Singleton has a static method getInstance and no public constructor. I want to test the logical part, test extraMethod without Data sort operation.
You could get away without PowerMock if you would spy your class under test and create a package level method that would be return the Singleton.
You still need to set-up what should happen when the sort method is invoked:
1) Class under test
public Data extraMethod(Data data) // interface Data
{
Data d = getSingleton().sort(data.get() , "desc");
//do something, logical
return d;
}
Singleton getSingleton(){
return Singleton.getInstance();
}
2) Test
#Spy
private MyClass myClassSpy = new MyClass();
#Mock
Singleton singletonStub;
#Mock
Data dataStub;
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
#Test
public void test() throws Exception{
// Arrange
doReturn(singletonStub).when(myClassSpy).getSingleton();
when(dataStub.get()).thenReturn(...);
when(singletonStub.sort(any(Data.class), "desc")).thenReturn(/* some data*/);
// Act and Assert
}
Related
I am trying to write unit test cases for one of the methods in code.Below is the method
public boolean isValid() {
if(object == null)
return false
//do something here and return value.
}
The object is created by this method which is done before without getter setter method.
private Object returnObject() {
object = Axis2ConfigurationContextFactory.getConfigurationContext();
return object;
}
When I try to test isValid(), the object is always null, so it never goes in the code to do something.
I was checking if there is any way to skip that line or make the object not null. I also tried creating an object using returnObject method. But it uses Axis library classes which throws error if it does not find certain data. What can be done in this case? I am dealing with legacy code so any pointers would be helpful.
Edit : Adding test implementation.
#PowerMockIgnore({ "javax.xml.*", "org.w3c.dom.*", "javax.management.*" })
public class ClassTest {
private ClassTest classTestObj;
#BeforeMethod
public void callClassConstructor() {
classTestObj = //call class constructor
}
#BeforeClass
public void setUpClass() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public boolean isValidTest() {
Boolean result = classTestObj.isValid();
Assert.assertEquals(result);
}
}
As I mentioned in the before comment, you can make use of MockedStatic to mock the static method - https://javadoc.io/static/org.mockito/mockito-core/4.4.0/org/mockito/Mockito.html#static_mocks
So your code will somewhat look like the below one if you are making use of Mockito instead of PowerMockito.
#RunWith(MockitoJUnitRunner.class)
public class ClassTest
{
#Mock
private Object mockAxis2ConfigurationContextFactoryObject;
#Test
public boolean isValidTest() {
try (MockedStatic<Axis2ConfigurationContextFactory> mockedStatic = mockStatic(Axis2ConfigurationContextFactory.class)) {
mockedStatic.when(()->Axis2ConfigurationContextFactory.getConfigurationContext()).thenReturn(mockAxis2ConfigurationContextFactoryObject);
Boolean result = classTestObj.isValid();
Assert.assertEquals(result);
}
}
Is there any way, using Mockito or PowerMockito, to intercept calls to non-static methods of an object, or at least of a singleton object?
An example is provided by the following classes:
public class Singleton {
private static Singleton INSTANCE = null;
private Singleton(Object parameter) {}
public static Singleton getInstance(Object parameter) {
if (INSTANCE == null) {
INSTANCE = new Singleton(parameter);
}
return INSTANCE;
}
public String process(String a, String b) {
return (a + b);
}
// Other methods
}
public class Foreign {
private Foreign() {}
public static void main(String[] args) {
System.out.println(Singleton.getInstance(new Object()).process("alpha", "beta"));
}
}
The Singleton object is created in a Foreign class, outside the control of some test code (not shown above). Neither of these two classes can be modified. The objective is to intercept calls to the non-static process() method in the test code so that, for certain values, a different result is returned, e.g. the call
Singleton.getInstance(new Object()).process("alpha", "beta");
mocked to return "alpha-beta" instead of the expected "alphabeta".
One solution could be intercepting the Singleton.getInstance() method to instantiate a custom subclass of the Singleton, e.g. using
public class SubSingleton extends Singleton {
public SubSingleton(Object parameter) {
super(parameter);
}
public String process(String a, String b) {
if ("alpha".equals(a) && "beta".equals(b)) {
return a + "-" + b;
}
return super.process(a + b);
}
}
Then, calls to the Singleton.process() method would be intercepted as in:
Object parameter = new Object();
PowerMockito.doReturn(new SubSingleton(parameter)).when(Singleton.class, "getInstance", parameter);
However, the Singleton class above only provides a private constructor, so it cannot be extended. Using PowerMockito.whenNew() to return a partial mock (spy) will also not work, since the Singleton class does not provide a no-args constructor.
Can the desired mocking be implemented in any other way? Can it be done for non-singleton classes?
Firstly, you can use whenNew for objects with constructor with some params:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Singleton.class)
public class SingletonPrivateNewTest {
#Mock
Singleton singletonMock;
#Before
public void setUp() throws Exception {
PowerMockito.whenNew(Singleton.class)
.withAnyArguments()
.thenReturn(singletonMock);
}
#Test
public void testMockNew() throws Exception {
Mockito.when(singletonMock.process(anyString(), anyString())).thenReturn("sasa");
Foreign.main(new String[0]);
}
}
Secondly, why not stub getInstance instead of new:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Singleton.class)
public class SingletonPrivateNewTest {
#Test
public void testMockNew() {
PowerMockito.mockStatic(Singleton.class);
Singleton singletonMock = Mockito.mock(Singleton.class);
PowerMockito.when(Singleton.getInstance(any())).thenReturn(singletonMock);
Mockito.when(singletonMock.process(anyString(), anyString())).thenReturn("sasa");
Foreign.main(new String[0]);
}
}
Thirdly, to intercept the process method:
create real singleton
create a mock singleton
mock static getInstance to return the mock. NOTE: you must call mockStatic after getting real instance.
use thenAnswer to check the arguments on process call
return desired answer if they match desired pattern
else call real method on real singleton
#RunWith(PowerMockRunner.class)
#PrepareForTest(Singleton.class)
public class SingletonPrivateNewTest {
#Test
public void testMockNew() {
var singletonReal = Singleton.getInstance(new Object());
var singletonMock = Mockito.mock(Singleton.class);
PowerMockito.mockStatic(Singleton.class);
PowerMockito.when(Singleton.getInstance(any())).thenReturn(singletonMock);
Mockito.when(singletonMock.process(anyString(), anyString())).thenAnswer((args) -> {
String a = args.getArgument(0);
String b = args.getArgument(1);
if ("alpha".equals(a) && "beta".equals(b)) {
return "sasa";
} else {
return singletonReal.process(a, b);
}
});
Foreign.main(new String[0]);
}
}
And finally, use a spy instead of a mock
#RunWith(PowerMockRunner.class)
#PrepareForTest(Singleton.class)
public class SingletonPrivateNewTest {
#Test
public void testMockNew() {
var singletonReal = Singleton.getInstance(new Object());
var singletonMock = Mockito.spy(singletonReal);
PowerMockito.mockStatic(Singleton.class);
PowerMockito.when(Singleton.getInstance(any())).thenReturn(singletonMock);
Mockito.when(singletonMock.process("alpha", "beta")).thenReturn("sasa");
// NOTE: real method is called for other args
Foreign.main(new String[0]);
}
}
Preconditions
I have the following class (fictional, just for demonstrating the problem):
public class MySingleton {
private static MySingleton sMySingleton;
private static List<String> sItemList;
private MySingleton(List<String> list) {
sItemList = list;
}
public static MySingleton getInstance(List<String> list) {
if (sMySingleton == null) {
sMySingleton = new MySingleton(list);
}
return sMySingleton;
}
public void addItem(String item) {
sItemList.add(item);
}
public void removeItem(String item) {
sItemList.remove(item);
}
}
And an according test class:
public class MySingletonTest {
private MySingleton mInstance;
private List<String> mList;
#Before
public void setup() {
mList = mock(List.class);
mInstance = MySingleton.getInstance(mList);
}
#Test
public void testAddItem() throws Exception {
String item = "Add";
mInstance.addItem(item);
verify(mList, times(1)).add(item);
}
#Test
public void testRemoveItem() throws Exception {
String item = "Remove";
mInstance.removeItem(item);
verify(mList, times(1)).remove(item);
}
}
Problem
If I now execute the complete test class, Mockito tells me for the test testRemoveItem() that there were 0 interactions with the mock.
How is that possible?
Note:
Please do not start of a discussion about the sense singletons.
This question is about Mockito and why its not working.
JUnit creates a new test class instance for every single test, which Mockito populates with a new mock instance for every single test. However, your singleton only ever initializes itself once, meaning that mList == MySingleton.sItemList during the first test but mList != MySingleton.sItemList for every test after that.
In other words, the interaction is happening, but by the second test, you're checking the wrong mock.
Though I know you're not here to debate the merits of this type of singleton, bear in mind that you might have a hard time replacing the instance in tests if you do it this way. Instead, consider making the singleton's constructor available (only) to your tests, and keeping the List (or other state) within the instance. That way you can create a brand new "Singleton" for every individual test.
My class structure is as follows:
public class MyParentClass {
void doSomethingParent() {
System.out.println("something in parent");
}
}
public class MyClass extends MyParentClass {
protected String createDummyRequest(Holder myHolder) {
//...
super.doSomethingParent();//I want to avoid this
//...
callingDB();
return "processedOutput";
}
private void callingDB() {
System.out.println("Calling to DB");
}
}
Then my unit test:
public class UnitTest {
public void testCreateDummyRequest() {
//create my mock holder
Holder mockHolder = new Holder();
MyClass mockObj = Mockito.mock(MyClass.class);
//mock doSomethingParent()
//mock callingDB()
//as mockObj is a fully mock, but I need to run my real method
//Mockito.when(mockObj.createDummyRequest(mockHolder)).thenCallRealMethod();
mockObj.createDummyRequest(mockHolder);
//Problem: doSomethingParent() is getting called though I have mocked it
}
}
How do I prevent the calling of the super.doSomethingParent() in my method? (method which I am writing my test)
With this class structure mocking and testing is real hard. If possible, I'd advice to change the structure as in mist cases a class structure that's hard to mock and test is equally hard to extend and maintain.
So if you could change your class structure to something similar to:
public class MyClass {
private DoSomethingProvider doSomethingProvider;
private DbConnector dbConnector;
public MyClass (DoSomethingProvider p, DbConnector c) {
doSomethingProvicer = p;
dbConnector = c;
}
protected String createDummyRequest(Holder myHolder){
//...
doSomethingProvider.doSomethingParent();
//...
dbConnector.callingDB();
return "processedOutput";
}
}
Then you could easily create your instance with mocks of DoSomethingProvider and DbConnector and voila....
If you can't change your class structure you need to use Mockito.spy instead of Mockito.mock to stub specific method calls but use the real object.
public void testCreateDummyRequest(){
//create my mock holder
Holder mockHolder = new Holder();
MyClass mockObj = Mockito.spy(new MyClass());
Mockito.doNothing().when(mockObj).doSomething();
mockObj.createDummyRequest(mockHolder);
}
Note: Using the super keyword prevents Mockito from stubbing that method call. I don't know if there is a way to stub calls to super. If possible (as in you didn't override the parent method in your class), just ommit the keyword.
I faced similar issue, so I find out that using spy() can hepld.
public class UnitTest {
private MyClass myObj;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
myObj= spy(new MyClass());
}
#Test
public void mockedSuperClassMethod(){
doNothing().when((MyParentClass )myObj).doSomethingParent();
//...
}
}
This approach works for me.
I found another approach, which turned out to be very useful in my case.
In the case I had, I needed to create a new class extending another, which included a very complex (legacy code) protected final method. Due to the complexity, it wasn't really possible to refactor to use composition, so here's what I came up with.
Let's say I have the following:
abstract class Parent {
public abstract void implementMe();
protected final void doComplexStuff( /* a long parameter list */) {
// very complex legacy logic
}
}
class MyNewClass extends Parent {
#Override
public void implementMe() {
// custom stuff
doComplexStuff(/* a long parameter list */); // calling the parent
// some more custom stuff
}
}
Here's how I rearranged this code:
abstract class Parent {
public abstract void implementMe();
protected final void doComplexStuff( /* a long parameter list */) {
// very complex legacy logic
}
}
interface ComplexStuffExecutor {
void executeComplexStuff(/* a long parameter list, matching the one from doComplexStuff */);
}
class MyNewClass extends Parent {
private final ComplexStuffExecutor complexStuffExecutor;
MyNewClass() {
this.complexStuffExecutor = this::doComplexStuff;
}
MyNewClass(ComplexStuffExecutor complexStuffExecutor) {
this.complexStuffExecutor = complexStuffExecutor;
}
#Override
public void implementMe() {
// custom stuff
complexStuffExecutor.doComplexStuff(/* a long parameter list */); // either calling the parent or the injected ComplexStuffExecutor
// some more custom stuff
}
}
When creating instance of MyNewClass for "production" purposes, I can use the default constructor.
When writing unit tests, however, I'd use the constructor, where I can inject ComplexStuffExecutor, provide a mock there and only test my custom logic from MyNewClass, i.e.:
class MyNewClassTest {
#Test
void testImplementMe() {
ComplexStuffExecutor complexStuffExecutor = Mockito.mock(ComplexStuffExecutor.class);
doNothing().when(complexStuffExecutor).executeComplexStuff(/* expected parameters */);
MyNewClass systemUnderTest = new MyNewClass(complexStuffExecutor);
// perform tests
}
}
At first glance, it seems like adding some boilerplate code just to make the code testable. However, I can also see it as an indicator of how the code should actually look like. Perhaps one day someone (who would find courage and budget ;) ) could refactor the code e.g. to implement the ComplexStuffExecutor with the logic from doComplexStuff from Parent, inject it into MyNewClass and get rid of inheritance.
Here is how it can be done
public class BaseController {
public void method() {
validate(); // I don't want to run this!
}
}
public class JDrivenController extends BaseController {
public void method(){
super.method()
load(); // I only want to test this!
}
}
#Test
public void testSave() {
JDrivenController spy = Mockito.spy(new JDrivenController());
// Prevent/stub logic in super.method()
Mockito.doNothing().when((BaseController)spy).validate();
// When
spy.method();
// Then
verify(spy).load();
}
Source: https://blog.jdriven.com/2013/05/mock-superclass-method-with-mockito/
Let's look at this piece of code :
public class A {
public void doSmth() { // pay attention - void method
// impl
}
}
public class B {
private A a_instance; // null
public void doSmthElse() {
a_instance.doSmth(); // NPE here without mock
// also do smth. else
}
}
Now, I have B b = new B(); and I want to test b.doSmthElse() , but I need to create a mock for a_instance object before, otherwise I will get NullPointerException ! How can I achieve this with EasyMock or PowerMock ???
#Test
public void testDoSomething()
{
// setup: sut
B b = new B();
A mockA = EasyMock.createMock(A.class);
b.setA_instance(mockA); // If you have a setter
// setup: expectations
mockA.doSmth();
// exercise
EasyMock.replay(mockA);
b.doSmthElse();
// verify
EasyMock.verify(mockA);
}
#Test
public void testDoSomething_setUsingReflection()
{
// setup: sut
B b = new B();
A mockA = EasyMock.createMock(A.class);
// Set the collaborator using a Spring reflection utility
ReflectionTestUtils.setField(b, "a_instance", mockA);
// setup: expectations
mockA.doSmth();
// exercise
EasyMock.replay(mockA);
b.doSmthElse();
// verify
EasyMock.verify(mockA);
}
You can use
instanceName.methodName();
Easymock.expectLastCall(); //for void methods this is how it is done
instanceName can be mocked or actualInstance.
If u can make the method static then it is easier with powermock
Powermock.mockStatic(ClassNameContainingStaticMethod)
All static methods get mocked directly
Word of Caution:- Converting a method to static can have issues in other parts.Do it carefully
Hope it helps.
All the best!
I don't see a reason why PowerMock is required here. You can achieve that with EasyMock itself.
#Test
public void testDoSmthElse() {
A a = EasyMock.createMock(A.class);
EasyMock.expect(a.doSmth()).andReturn(/*some value */);
EasyMock.replay(a);
B b = new B();
Object whatever = b.doSmthElse();
assert(); // psuedo-line. Add whatever assertion required
}
Note: Import appropriate classes