Spy a class without PowerMock - java

I don't want to use powermock anymore. Because junit5 started mocking static classes. So i am trying to get rid of powermock methods.
While i was using PowerMock, i could easily spy a class that has a private constructor, and then i was calling the static methods.
This is a part of my code ( When i was using PowerMock )
#RunWith(PowerMockRunner.class)
#PrepareForTest(MessageValidationUtils.class)
public class MessageValidationServiceTest {
#Mock
private CheckpointCustomerService checkpointCustomerService;
#Mock
private ProductClientService productClientService;
#Before
public void setUp() {
MockitoAnnotations.openMocks(this);
PowerMockito.spy(MessageValidationUtils.class);
}
After i make a spy object of MessageValidationUtils.class, i was testing this:
when(MessageValidationUtils.validateTelegramKeyMap(messageProcessDto.getMessageMessageType(),
messageProcessDto.getMessageKeyValueMap())).thenAnswer((Answer<Boolean>) invocation -> true);
After some research i couldn't find anything related to spy a class that has a private constructor and static methods.

During mockStatic definition in Mockito you can specify setting to perform real execution by default Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS). In this way, your static mock will work like Spy.
Let's create simple Utils class for testing.
public class Utils {
public static String method1() {
return "Original mehtod1() value";
}
public static String method2() {
return "Original mehtod2() value";
}
public static String method3() {
return method2();
}
}
Make mock for method2 and perform real execution of method1 and method3
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
public class SpyStaticTest {
#Test
public void spy_static_test() {
try (MockedStatic<Utils> utilities = Mockito.mockStatic(Utils.class, Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS))) {
utilities.when(Utils::method2).thenReturn("static mock");
Assertions.assertEquals(Utils.method1(), "Original mehtod1() value");
Assertions.assertEquals(Utils.method2(), "static mock");
Assertions.assertEquals(Utils.method3(), "static mock");
}
}
}
Example for your class:
#Test
public void test() {
try (MockedStatic<MessageValidationUtils> utilities = Mockito.mockStatic(MessageValidationUtils.class, Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS))) {
utilities.when(() -> MessageValidationUtils.validateTelegramKeyMap(messageProcessDto.getMessageMessageType(),
messageProcessDto.getMessageKeyValueMap())).thenAnswer((Answer<Boolean>) invocation -> true);
//perform testing of your service which uses MessageValidationUtils
}
}
UPDATE:
Example to use mockStatic in #BeforeEach
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
public class SpyStaticTest {
MockedStatic<Utils> utilities;
#BeforeEach
public void setUp() {
utilities = Mockito.mockStatic(Utils.class, Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS));
}
#Test
public void spy_static_test1() {
utilities.when(Utils::method2).thenReturn("static mock");
Assertions.assertEquals(Utils.method1(), "Original mehtod1() value");
Assertions.assertEquals(Utils.method2(), "static mock");
Assertions.assertEquals(Utils.method3(), "static mock");
}
#Test
public void spy_static_test2() {
utilities.when(Utils::method1).thenReturn("static mock");
Assertions.assertEquals(Utils.method1(), "static mock");
Assertions.assertEquals(Utils.method2(), "Original mehtod2() value");
Assertions.assertEquals(Utils.method3(), "Original mehtod2() value");
}
#AfterEach
public void afterTest() {
utilities.close();
}
}
UPDATE:
Mockito does not provide method for static Spy creation, but you can define own utils and implemet spy static definition there.
import org.mockito.MockedStatic;
import org.mockito.Mockito;
public class MockitoUtils {
public static <T> MockedStatic<T> spyStatic(Class<T> classToMock) {
return Mockito.mockStatic(classToMock, Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS));
}
}
In this way your tests will look more clear:
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import static com.test.MockitoUtils.spyStatic;
public class SpyStaticTest {
MockedStatic<Utils> utilsSpy;
#BeforeEach
public void setUp() {
utilsSpy = spyStatic(Utils.class);
}
#Test
public void spy_static_test1() {
utilsSpy.when(Utils::method2).thenReturn("static mock");
Assertions.assertEquals(Utils.method1(), "Original mehtod1() value");
Assertions.assertEquals(Utils.method2(), "static mock");
Assertions.assertEquals(Utils.method3(), "static mock");
}
#Test
public void spy_static_test2() {
utilsSpy.when(Utils::method1).thenReturn("static mock");
Assertions.assertEquals(Utils.method1(), "static mock");
Assertions.assertEquals(Utils.method2(), "Original mehtod2() value");
Assertions.assertEquals(Utils.method3(), "Original mehtod2() value");
}
#AfterEach
public void afterTest() {
utilsSpy.close();
}
}

Related

How to test java class having initialisation in constructor

I have a java class whose constructor looks like this
private SomeManager someManager;
public MyService() {
this.someManager = ManagerHandler.getDefault();
}
The issue is that while testing ManagerHandler is not initialised so I am not able to create new object of this class to test its method. I am using mockito for testing. I am not able to understand How to mock a parameter which I am not passing in the constructor.
Is there anyway I can mock someManager using PowerMock?
You can use InjectMocks annotation. See below example:
MyService class:
public class MyService {
ManagerHandler someManager;
public MyService() {
this.someManager = ManagerHandler.getDefault();
}
// other methods
public String greetUser(String user) {
return someManager.sayHello(user) + ", Good Morning!";
}
}
ManagerHandler class:
public class ManagerHandler {
public static ManagerHandler getDefault() {
return new ManagerHandler();
}
public String sayHello(String userName) {
return "Hello " + userName;
}
}
TestClass:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class TestClass {
#Mock
ManagerHandler someManager;
#InjectMocks
MyService myService = new MyService();
#Test
public void test() {
//mock methods of ManagerHandler
Mockito.when(someManager.sayHello("Alice")).thenReturn("Hello Alice");
assertEquals("Hello Alice, Good Morning!", myService.greetUser("Alice"));
}
}

Can I mock some static methods only using powermock+mockito+junit?

I am writing a test using Junit + Mockito + Powermock.
I have a class like following which I want to test:
public class MyUtils {
public static Object method1() {} //I want to mock this only
public static void method2() {} //I want to keep this as is during my test.
public static void method3() {} //I want to keep this as is during my test.
}
I want to mock only method1 but not method2 or method3.
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyUtils.class)
public class MyTest {
#Before
public void setUpBeforeClass() throws Exception {
PowerMockito.mockStatic(MyUtils.class);
}
#Test
public void test1() throws Exception {
when(MyUtils.method1()).thenReturn(something);
MyUtils.method3(); //method3 is getting mocked with an empty implementation by PowerMockito
}
...
}
Can I have some methods mocked and some not be mocked i.e. they keep their original implementation during the test? Is this possible with Mockito + Powermock?
My test may not look very elegant but I have simplified my usecase before posting here.
Thank you.
Yes it is possible to mock static methods using Powermock and JUnit as below:
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.powermock.api.mockito.PowerMockito.*;
#RunWith(PowerMockRunner.class)
#PrepareForTest(IDGenerator.class)
public class UserDAOTest {
#Test
public void createShouldReturnAUserId() {
UserDAO dao = new UserDAO();
mockStatic(IDGenerator.class);
when(IDGenerator.generateID()).thenReturn(1);
int result = dao.create(new User());
assertEquals(1, result);
verifyStatic();
}
}
public final class IDGenerator {
static int i;
public static final int generateID() {
return i++;
}
}
public class UserDAO {
public int create(User user){
int id = IDGenerator.generateID();
//Save the user object to the db
return id;
}
}
public class User {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
Hope it helps!
If you have way more methods that you want to keep with real implementation than ones that need to be mocked (especially when its only one in your case) then I would go for spy instead of mock:
import static org.powermock.api.mockito.PowerMockito.spy;
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyUtils.class)
public class MyTest {
#Before
public void setUpBeforeClass() throws Exception {
spy(MyUtils.class);
}
#Test
public void test1() throws Exception {
doReturn(something).when(MyUtils.class, "method1");
MyUtils.method3(); // this will be a real call
}
...
}
Now all the methods except method1 will be called with real implementation.

i am getting "java.lang.Exception: Method tearDown should have no parameters" for below code & result.getStatus is null

i am getting "java.lang.Exception: Method tearDown should have no parameters" for below code & result.getStatus is null
i have JUnit to run cases
package com;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
public class DeleteLeter {
#Test
public void testw() throws Exception{
WebDriver driver = new FirefoxDriver();
driver.get("http://e4allapac");
int a =10;
int b=20;
Assert.assertEquals(a, b);
}
#After
public void tearDown(ITestResult result){
System.out.println(result.getStatus());
if(ITestResult.FAILURE==result.getStatus())
System.out.println("Fail");
}
}
It sounds like you want to implement a TestWatcher rule - http://junit.org/junit4/javadoc/4.12/index.html.
The basic idea is that you create a class which extends the TestWatcher class, attach it as a #Rule to your test suite and then it will get notified when a test fails.
public class MyWatcher extends TestWatcher {
#Override
protected void failed(Throwable e, Description description) {
// do whatever Selenium magic here.
}
}
public class MyTests {
#Rule
public final MyWatcher myWatcher = new MyWatcher();
#Test
public void testMethod() {
// test stuff goes in here
}
}

Change value of guice instance on runtime

I´m using google guice to inject this class example
class A {
String a;
}
Then is injected in my class B
class B {
#Inject A aInstance;
public void checkValue(){
System.out.println(aInstance.a);
}
}
Maybe using aspectJ, but what I would like is, that one test of mine, would get this A instance and would set the "a" string as "foo", before execute the test that cover the B class, so when the B class invoke checkValue this one would print "foo"
You mention the word test in your question - if you are writing a jUnit test for B you could perform the injection in an #Before clause, as demonstrated here.
private Injector injector;
#Before
public void init() throws Exception {
injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(A.class).to(MockedInstanceOfAWithValueFoo.class);
}
});
}
You could also call
bind(A.class).toInstance(new MockedInstanceOfAWithValueFoo());
If we assume that A has a constructor by which we can define A.a, the mocked instance could look like this:
public class MockedInstanceOfAWithValueFoo extends A{
public MockedInstanceOfAWithValueFoo() {
super("foo");
}
}
Again, you could make your mocked class accept the value of A.a through a constructor to make the creation of B (and the associated value of A.a) more dynamic.
With Mockito:
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class MyTest {
#Mock
A mockA;
#InjectMocks
B mockB;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
mockA.a = "Foo";
//when(mockA.getA()).thenReturn("Foo"); //if you use getter
}
#Test
public void myTest() {
assertNotNull(mockA);
assertNotNull(mockA.a);
assertNotNull(mockB);
assertNotNull(mockB.ainstance);
mockB.checkValue();
}
}

How to mock private method for testing using PowerMock?

I have a class which I would like to test with a public method that calls private one. I'd like to assume that private method works correctly. For example, I'd like something like doReturn....when.... I found that there is possible solution using PowerMock, but this solution doesn't work for me.
How It can be done? Did anybody have this problem?
I don't see a problem here. With the following code using the Mockito API, I managed to do just that :
public class CodeWithPrivateMethod {
public void meaningfulPublicApi() {
if (doTheGamble("Whatever", 1 << 3)) {
throw new RuntimeException("boom");
}
}
private boolean doTheGamble(String whatever, int binary) {
Random random = new Random(System.nanoTime());
boolean gamble = random.nextBoolean();
return gamble;
}
}
And here's the JUnit test :
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.support.membermodification.MemberMatcher.method;
#RunWith(PowerMockRunner.class)
#PrepareForTest(CodeWithPrivateMethod.class)
public class CodeWithPrivateMethodTest {
#Test(expected = RuntimeException.class)
public void when_gambling_is_true_then_always_explode() throws Exception {
CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());
when(spy, method(CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class))
.withArguments(anyString(), anyInt())
.thenReturn(true);
spy.meaningfulPublicApi();
}
}
A generic solution that will work with any testing framework (if your class is non-final) is to manually create your own mock.
Change your private method to protected.
In your test class extend the class
override the previously-private method to return whatever constant you want
This doesn't use any framework so its not as elegant but it will always work: even without PowerMock. Alternatively, you can use Mockito to do steps #2 & #3 for you, if you've done step #1 already.
To mock a private method directly, you'll need to use PowerMock as shown in the other answer.
For some reason Brice's answer is not working for me. I was able to manipulate it a bit to get it to work. It might just be because I have a newer version of PowerMock. I'm using 1.6.5.
import java.util.Random;
public class CodeWithPrivateMethod {
public void meaningfulPublicApi() {
if (doTheGamble("Whatever", 1 << 3)) {
throw new RuntimeException("boom");
}
}
private boolean doTheGamble(String whatever, int binary) {
Random random = new Random(System.nanoTime());
boolean gamble = random.nextBoolean();
return gamble;
}
}
The test class looks as follows:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.doReturn;
#RunWith(PowerMockRunner.class)
#PrepareForTest(CodeWithPrivateMethod.class)
public class CodeWithPrivateMethodTest {
private CodeWithPrivateMethod classToTest;
#Test(expected = RuntimeException.class)
public void when_gambling_is_true_then_always_explode() throws Exception {
classToTest = PowerMockito.spy(classToTest);
doReturn(true).when(classToTest, "doTheGamble", anyString(), anyInt());
classToTest.meaningfulPublicApi();
}
}
i know a way ny which you can call you private function to test in mockito
#Test
public void commandEndHandlerTest() throws Exception
{
Method retryClientDetail_privateMethod =yourclass.class.getDeclaredMethod("Your_function_name",null);
retryClientDetail_privateMethod.setAccessible(true);
retryClientDetail_privateMethod.invoke(yourclass.class, null);
}
With no argument:
ourObject = PowerMockito.spy(new OurClass());
when(ourObject , "ourPrivateMethodName").thenReturn("mocked result");
With String argument:
ourObject = PowerMockito.spy(new OurClass());
when(ourObject, method(OurClass.class, "ourPrivateMethodName", String.class))
.withArguments(anyString()).thenReturn("mocked result");
Something to Consider
Make sure the private function is calling another public function and you can proceed only mocking the public function.

Categories