For what reason should I mock? - java

I am new to Mockito and PowerMockito as well. I found out that I can not test static methods with pure Mockito so I need to user PowerMockito (right?).
I have very simple class called Validate with this very easy method
public class Validate {
public final static void stateNotNull(
final Object object,
final String message) {
if (message == null) {
throw new IllegalArgumentException("Exception message is a null object!");
}
if (object == null) {
throw new IllegalStateException(message);
}
}
So I need to verify that:
1) When I call that static method on null message argument, IllegalArgumentException is called
2) When I call that static method on null object argument, IllegalStateException is called
From what I got so far, I wrote this test:
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.isNull;
import org.junit.Before;
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 org.testng.annotations.Test;
#RunWith(PowerMockRunner.class)
#PrepareForTest(Validate.class)
public class ValidateTestCase {
#Test(expectedExceptions = { IllegalStateException.class })
public void stateNotNullTest() throws Exception {
PowerMockito.mockStatic(Validate.class);
Validate mock = PowerMockito.mock(Validate.class);
PowerMockito.doThrow(new IllegalStateException())
.when(mock)
.stateNotNull(isNull(), anyString());
Validate.stateNotNull(null, null);
}
}
So this says that I mock Validate class and I am checking that when mock is called on that method with null argument as an object and any string as a message, an IllegalStateException is thrown.
Now, I really don't get it. Why I just can't call that method directly, dropping the whole voodoo magic around mocking that static class? It seems to me that unless I call Validate.stateNotNull that test passes anyway ... For what reason should I mock it?

You should not mock the classes and methods you are testing. You should only mock methods that are needed to perform the test itself.
For example, if you need some objects from a web service to perform a test, you could mock the web service calls, so you don't need to actually call the web service.

First, decide what your objective is and what you want to test. Your test isn't testing your Validate class method, it's creating a mock that behaves like that method, as Fortega points out. Identify what it is you are testing (the object under test) and what it is you need in order to perform the test (the collaborators), then look at the collaborators and decide whether they are things that are easy to create or if you need to mock them.
For something like this class which has no dependencies on anything, I would recommend doing without mocks entirely. There is nothing here that needs mocking, the test can be written like this:
import static org.junit.Assert.*;
public class ValidateTestCase {
#Test
public void testHappyPath() throws Exception {
Validate.stateNotNull("", "");
}
#Test
public void testNullMessage() throws Exception {
try {
Validate.stateNotNull(null, null);
fail();
}
catch (IllegalStateException e) {
String expected = "Exception message is a null object!"
assertEquals(expected, e.getMessage());
}
}
#Test(expected=IllegalStateException.class)
public void testNullObject() throws Exception {
Validate.stateNotNull(null, "test");
}
}
and that tells you whether the code does what you want it to.
Don't mock unless there is some dependency that you want to avoid introducing to the test due to it being either an external resource (like a filesystem or database) or some complex subsystem. The mock frameworks can be very useful but they add complexity, they can over-specify the behavior of the things they are testing, making the tests brittle, and they can make tests hard to read. Do without them if you can.

Related

Unable to mock method call response in mockito [duplicate]

I've written a factory to produce java.sql.Connection objects:
public class MySQLDatabaseConnectionFactory implements DatabaseConnectionFactory {
#Override public Connection getConnection() {
try {
return DriverManager.getConnection(...);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
I'd like to validate the parameters passed to DriverManager.getConnection, but I don't know how to mock a static method. I'm using JUnit 4 and Mockito for my test cases. Is there a good way to mock/verify this specific use-case?
Use PowerMockito on top of Mockito.
Example code:
#RunWith(PowerMockRunner.class)
#PrepareForTest(DriverManager.class)
public class Mocker {
#Test
public void shouldVerifyParameters() throws Exception {
//given
PowerMockito.mockStatic(DriverManager.class);
BDDMockito.given(DriverManager.getConnection(...)).willReturn(...);
//when
sut.execute(); // System Under Test (sut)
//then
PowerMockito.verifyStatic();
DriverManager.getConnection(...);
}
More information:
Why doesn't Mockito mock static methods?
Mocking of static methods in Mockito is possible since Mockito 3.4.0.
For more details see:
https://github.com/mockito/mockito/releases/tag/v3.4.0
https://github.com/mockito/mockito/issues/1013
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#static_mocks
assertEquals("foo", Foo.method());
try (MockedStatic mocked = mockStatic(Foo.class)) {
mocked.when(Foo::method).thenReturn("bar");
assertEquals("bar", Foo.method());
mocked.verify(Foo::method);
}
assertEquals("foo", Foo.method());
In your case, something like this:
#Test
public void testStaticMockWithVerification() throws SQLException {
try (MockedStatic<DriverManager> dummy = Mockito.mockStatic(DriverManager.class)) {
DatabaseConnectionFactory factory = new MySQLDatabaseConnectionFactory();
dummy.when(() -> DriverManager.getConnection("arg1", "arg2", "arg3"))
.thenReturn(new Connection() {/*...*/});
factory.getConnection();
dummy.verify(() -> DriverManager.getConnection(eq("arg1"), eq("arg2"), eq("arg3")));
}
}
NOTE: mocking STATIC METHODS requires mockito-inline dependency instead of mockito-core.
For JUnit5 also add this:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
The typical strategy for dodging static methods that you have no way of avoiding using, is by creating wrapped objects and using the wrapper objects instead.
The wrapper objects become facades to the real static classes, and you do not test those.
A wrapper object could be something like
public class Slf4jMdcWrapper {
public static final Slf4jMdcWrapper SINGLETON = new Slf4jMdcWrapper();
public String myApisToTheSaticMethodsInSlf4jMdcStaticUtilityClass() {
return MDC.getWhateverIWant();
}
}
Finally, your class under test can use this singleton object by, for example,
having a default constructor for real life use:
public class SomeClassUnderTest {
final Slf4jMdcWrapper myMockableObject;
/** constructor used by CDI or whatever real life use case */
public myClassUnderTestContructor() {
this.myMockableObject = Slf4jMdcWrapper.SINGLETON;
}
/** constructor used in tests*/
myClassUnderTestContructor(Slf4jMdcWrapper myMock) {
this.myMockableObject = myMock;
}
}
And here you have a class that can easily be tested, because you do not directly use a class with static methods.
If you are using CDI and can make use of the #Inject annotation then it is even easier.
Just make your Wrapper bean #ApplicationScoped, get that thing injected as a collaborator (you do not even need messy constructors for testing), and go on with the mocking.
I had a similar issue. The accepted answer did not work for me, until I made the change: #PrepareForTest(TheClassThatContainsStaticMethod.class), according to PowerMock's documentation for mockStatic.
And I don't have to use BDDMockito.
My class:
public class SmokeRouteBuilder {
public static String smokeMessageId() {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
log.error("Exception occurred while fetching localhost address", e);
return UUID.randomUUID().toString();
}
}
}
My test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest(SmokeRouteBuilder.class)
public class SmokeRouteBuilderTest {
#Test
public void testSmokeMessageId_exception() throws UnknownHostException {
UUID id = UUID.randomUUID();
mockStatic(InetAddress.class);
mockStatic(UUID.class);
when(InetAddress.getLocalHost()).thenThrow(UnknownHostException.class);
when(UUID.randomUUID()).thenReturn(id);
assertEquals(id.toString(), SmokeRouteBuilder.smokeMessageId());
}
}
As mentioned before you can not mock static methods with mockito.
If changing your testing framework is not an option you can do the following:
Create an interface for DriverManager, mock this interface, inject it via some kind of dependency injection and verify on that mock.
For those who use JUnit 5, Powermock is not an option. You'll require the following dependencies to successfully mock a static method with just Mockito.
testCompile group: 'org.mockito', name: 'mockito-core', version: '3.6.0'
testCompile group: 'org.mockito', name: 'mockito-junit-jupiter', version: '3.6.0'
testCompile group: 'org.mockito', name: 'mockito-inline', version: '3.6.0'
mockito-junit-jupiter add supports for JUnit 5.
And support for mocking static methods is provided by mockito-inline dependency.
Example:
#Test
void returnUtilTest() {
assertEquals("foo", UtilClass.staticMethod("foo"));
try (MockedStatic<UtilClass> classMock = mockStatic(UtilClass.class)) {
classMock.when(() -> UtilClass.staticMethod("foo")).thenReturn("bar");
assertEquals("bar", UtilClass.staticMethod("foo"));
}
assertEquals("foo", UtilClass.staticMethod("foo"));
}
The try-with-resource block is used to make the static mock remains temporary, so it's mocked only within that scope.
When not using a try block, make sure to close the mock, once you are done with the assertions.
MockedStatic<UtilClass> classMock = mockStatic(UtilClass.class)
classMock.when(() -> UtilClass.staticMethod("foo")).thenReturn("bar");
assertEquals("bar", UtilClass.staticMethod("foo"));
classMock.close();
Mocking void methods:
When mockStatic is called on a class, all the static void methods in that class automatically get mocked to doNothing().
Observation : When you call static method within a static entity, you need to change the class in #PrepareForTest.
For e.g. :
securityAlgo = MessageDigest.getInstance(SECURITY_ALGORITHM);
For the above code if you need to mock MessageDigest class, use
#PrepareForTest(MessageDigest.class)
While if you have something like below :
public class CustomObjectRule {
object = DatatypeConverter.printHexBinary(MessageDigest.getInstance(SECURITY_ALGORITHM)
.digest(message.getBytes(ENCODING)));
}
then, you'd need to prepare the class this code resides in.
#PrepareForTest(CustomObjectRule.class)
And then mock the method :
PowerMockito.mockStatic(MessageDigest.class);
PowerMockito.when(MessageDigest.getInstance(Mockito.anyString()))
.thenThrow(new RuntimeException());
You can do it with a little bit of refactoring:
public class MySQLDatabaseConnectionFactory implements DatabaseConnectionFactory {
#Override public Connection getConnection() {
try {
return _getConnection(...some params...);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//method to forward parameters, enabling mocking, extension, etc
Connection _getConnection(...some params...) throws SQLException {
return DriverManager.getConnection(...some params...);
}
}
Then you can extend your class MySQLDatabaseConnectionFactory to return a mocked connection, do assertions on the parameters, etc.
The extended class can reside within the test case, if it's located in the same package (which I encourage you to do)
public class MockedConnectionFactory extends MySQLDatabaseConnectionFactory {
Connection _getConnection(...some params...) throws SQLException {
if (some param != something) throw new InvalidParameterException();
//consider mocking some methods with when(yourMock.something()).thenReturn(value)
return Mockito.mock(Connection.class);
}
}
I also wrote a combination of Mockito and AspectJ: https://github.com/iirekm/varia/tree/develop/ajmock
Your example becomes:
when(() -> DriverManager.getConnection(...)).thenReturn(...);
Mockito cannot capture static methods, but since Mockito 2.14.0 you can simulate it by creating invocation instances of static methods.
Example (extracted from their tests):
public class StaticMockingExperimentTest extends TestBase {
Foo mock = Mockito.mock(Foo.class);
MockHandler handler = Mockito.mockingDetails(mock).getMockHandler();
Method staticMethod;
InvocationFactory.RealMethodBehavior realMethod = new InvocationFactory.RealMethodBehavior() {
#Override
public Object call() throws Throwable {
return null;
}
};
#Before
public void before() throws Throwable {
staticMethod = Foo.class.getDeclaredMethod("staticMethod", String.class);
}
#Test
public void verify_static_method() throws Throwable {
//register staticMethod call on mock
Invocation invocation = Mockito.framework().getInvocationFactory().createInvocation(mock, withSettings().build(Foo.class), staticMethod, realMethod,
"some arg");
handler.handle(invocation);
//verify staticMethod on mock
//Mockito cannot capture static methods so we will simulate this scenario in 3 steps:
//1. Call standard 'verify' method. Internally, it will add verificationMode to the thread local state.
// Effectively, we indicate to Mockito that right now we are about to verify a method call on this mock.
verify(mock);
//2. Create the invocation instance using the new public API
// Mockito cannot capture static methods but we can create an invocation instance of that static invocation
Invocation verification = Mockito.framework().getInvocationFactory().createInvocation(mock, withSettings().build(Foo.class), staticMethod, realMethod,
"some arg");
//3. Make Mockito handle the static method invocation
// Mockito will find verification mode in thread local state and will try verify the invocation
handler.handle(verification);
//verify zero times, method with different argument
verify(mock, times(0));
Invocation differentArg = Mockito.framework().getInvocationFactory().createInvocation(mock, withSettings().build(Foo.class), staticMethod, realMethod,
"different arg");
handler.handle(differentArg);
}
#Test
public void stubbing_static_method() throws Throwable {
//register staticMethod call on mock
Invocation invocation = Mockito.framework().getInvocationFactory().createInvocation(mock, withSettings().build(Foo.class), staticMethod, realMethod,
"foo");
handler.handle(invocation);
//register stubbing
when(null).thenReturn("hey");
//validate stubbed return value
assertEquals("hey", handler.handle(invocation));
assertEquals("hey", handler.handle(invocation));
//default null value is returned if invoked with different argument
Invocation differentArg = Mockito.framework().getInvocationFactory().createInvocation(mock, withSettings().build(Foo.class), staticMethod, realMethod,
"different arg");
assertEquals(null, handler.handle(differentArg));
}
static class Foo {
private final String arg;
public Foo(String arg) {
this.arg = arg;
}
public static String staticMethod(String arg) {
return "";
}
#Override
public String toString() {
return "foo:" + arg;
}
}
}
Their goal is not to directly support static mocking, but to improve its public APIs so that other libraries, like Powermockito, don't have to rely on internal APIs or directly have to duplicate some Mockito code. (source)
Disclaimer: Mockito team thinks that the road to hell is paved with static methods. However, Mockito's job is not to protect your code from static methods. If you don’t like your team doing static mocking, stop using Powermockito in your organization. Mockito needs to evolve as a toolkit with an opinionated vision on how Java tests should be written (e.g. don't mock statics!!!). However, Mockito is not dogmatic. We don't want to block unrecommended use cases like static mocking. It's just not our job.
To mock static method you should use a Powermock look at:
https://github.com/powermock/powermock/wiki/MockStatic.
Mockito doesn't provide this functionality.
You can read nice a article about mockito:
http://refcardz.dzone.com/refcardz/mockito
I found one solution in Mockito. This feature comes with a version only from 3.4.0
https://asolntsev.github.io/en/2020/07/11/mockito-static-methods/
dependency
In your build.gradle replace mockito-core:3.3.3 by mockito-inline:3.4.0:
testImplementation('org.mockito:mockito-inline:3.4.0')
what are we going to mock
class Buddy
{
static String name()
{
return "John";
}
}
Mock the static method
#Test
void lookMomICanMockStaticMethods()
{
assertThat(Buddy.name()).isEqualTo("John");
try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class))
{
theMock.when(Buddy::name).thenReturn("Rafael");
assertThat(Buddy.name()).isEqualTo("Rafael");
}
assertThat(Buddy.name()).isEqualTo("John");
}
I think this could help us.
Since that method is static, it already has everything you need to use it, so it defeats the purpose of mocking.
Mocking the static methods is considered to be a bad practice.
If you try to do that, it means there is something wrong with the way you want to perform testing.
Of course you can use PowerMockito or any other framework capable of doing that, but try to rethink your approach.
For example: try to mock/provide the objects, which that static method consumes instead.
When you try to mock the static method, you have to write the test inside the try block. because It's important to note that scoped mocks must be closed by the entity that activates the mock.
try (MockedStatic<Tester> tester = Mockito.mockStatic(Tester.class)) {
tester.when(() -> Tester.testStatic("Testing..")).thenReturn(mock(ReturnObject.class));
//Here you have to write the test cases
}
In the above example, we have to mock the Tester Class testStatic Method with input param as "Testing...". Here, this method will return a ReturnObject class type object. Hence we write mockito when chain like above.
Don't forget to add below dependency in your Gradle/maven
testImplementation 'org.mockito:mockito-inline:4.3.1'
Use JMockit framework. It worked for me. You don't have to write statements for mocking DBConenction.getConnection() method. Just the below code is enough.
#Mock below is mockit.Mock package
Connection jdbcConnection = Mockito.mock(Connection.class);
MockUp<DBConnection> mockUp = new MockUp<DBConnection>() {
DBConnection singleton = new DBConnection();
#Mock
public DBConnection getInstance() {
return singleton;
}
#Mock
public Connection getConnection() {
return jdbcConnection;
}
};
There is an easy solution by using java FunctionalInterface and then add that interface as dependency for the class you are trying to unit test.
For mocking static functions i was able to do it that way:
create a wrapper function in some helper class/object. (using a name variant might be beneficial for keeping things separated and maintainable.)
use this wrapper in your codes. (Yes, codes need to be realized with testing in mind.)
mock the wrapper function.
wrapper code snippet (not really functional, just for illustration)
class myWrapperClass ...
def myWrapperFunction (...) {
return theOriginalFunction (...)
}
of course having multiple such functions accumulated in a single wrapper class might be beneficial in terms of code reuse.
Here I share my mockito MockStatic solution based on an extension as promised in my answer to leokom's solution.
So, why does Mockito choose try-with-resources? Well, simply because they want to keep a tidy ship. That is good programming after all. Try-with-resources allows construction with guaranteed calling of the close method. But in JUnit we already have that in BeforeEach and AfterEach. And one can easily add these for a generic purpose to each test class using an Extension that implements BeforeEachCallback and AfterEachCallback.
So much for the theory. Let's make a static mock for
Instant.now()
I started with an annotation to be able to mark the fields in my test class that I want to use as static mocks.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface StaticMock {
}
This allows me to create a field in my test class for static mocking that I can easily find in my Extension class.
#StaticMock
private MockedStatic<Instant> staticInstantMock;
I added the Extension I created to my test class. You have two options.
Create an Extension for this purpose and add it to the class next to MockitoExtension, which you also need.
Create an Extension and have it inherit from MockitoExtension. Now you can replace MockitoExtension on your test class.
I used the latter of the two.
#ExtendWith({CompanyMockitoExtension.class})
class MyExtendedTestClass {
Now we need something to be returned for the static when it's called:
#Mock
private Instant now;
staticInstantMock.when(Instant::now).thenReturn(now);
The whole test class:
#ExtendWith({CompanyMockitoExtension.class})
class MyExtendedTestClass {
#StaticMock
private MockedStatic<Instant> staticInstantMock;
#Mock
private Instant now;
#Test
void myTestMethod() {
staticInstantMock.when(Instant::now).thenReturn(now);
assertThat(Instant::now).isSameAs(now); // This would normally happen in the class you are testing...
}
}
Now let's take a look at the Extension class.
import static org.mockito.Mockito.mockStatic;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
public class CompanyMockitoExtension extends MockitoExtension {
#Override
public void beforeEach(ExtensionContext context) {
super.beforeEach(context); // Don't forget to call the super!!
if (context.getTestInstance().isEmpty()) { // Just to be sure...
return;
}
// Get the unit test instance
Object testSubject = context.getTestInstance().get();
initializeStaticMocks(testSubject);
}
private void initializeStaticMocks(Object testSubject) {
// Find all fields that I want to static mock
List<Field> staticMockFields = ReflectionHelper.getFieldsWithAnnotation(testSubject, StaticMock.class);
staticMockFields.forEach(field -> initializeStaticMock(field, testSubject));
}
private void initializeStaticMock(Field field, Object testSubject) {
// Get the type of the static mock. It is within the generic MockedStatic<> class type.
Class<?> typeForStaticMock = (Class<?>) ReflectionHelper.getTypesForGeneric(field)[0];
try {
// Now set the field with the mockStatic method of Mockito.
field.setAccessible(true);
field.set(testSubject, mockStatic(typeForStaticMock));
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to instantiate Static Mock with type: " + typeForStaticMock.getName());
}
}
#Override
public void afterEach(ExtensionContext context) {
super.afterEach(context); // Again, do not forget to call the super.
if (context.getTestInstance().isEmpty()) {
return;
}
Object testSubject = context.getTestInstance().get();
closeStaticMocks(testSubject); // Close all static mocks.
}
private void closeStaticMocks(Object testSubject) {
// Again find all fields we annotated
List<Field> staticMockFields = ReflectionHelper.getFieldsWithAnnotation(testSubject, StaticMock.class);
staticMockFields.forEach(field -> closeStaticMock(field, testSubject));
}
private void closeStaticMock(Field field, Object testSubject) {
// Get the instance and simply call close.
MockedStatic<?> mockedStaticInstance = ReflectionHelper.getFieldInstance(field, testSubject, MockedStatic.class);
mockedStaticInstance.close();
}
}
The nice thing about this extension is that you can add additional mocking stuff. I added verification of no more interactions on all mocks in the AfterEach. This is now automatic when we use this extension. I also added similar behavior for construction mocking as for the static mocking.
As you see, I made my own reflection helper class. I know there are some standard reflection helper classes and those might be better. Here is mine for this purpose.
public class ReflectionHelper {
public static List<Field> getFieldsWithAnnotation(
Object testSubject,
Class<? extends Annotation> annotationType
) {
Class<?> testSubjectClass = testSubject.getClass();
return Arrays.stream(testSubjectClass.getDeclaredFields())
.filter(field -> field.isAnnotationPresent(annotationType))
.collect(toUnmodifiableList());
}
public static List<Field> getCollectionFields(Object testSubject) {
Class<?> testSubjectClass = testSubject.getClass();
return Arrays.stream(testSubjectClass.getDeclaredFields())
.filter(field -> Collection.class.isAssignableFrom(field.getType()))
.collect(toUnmodifiableList());
}
#SuppressWarnings("unchecked")
public static <T> T getFieldInstance(Field field, Object testSubject, Class<T> type) {
return (T) getFieldInstance(field, testSubject);
}
public static Object getFieldInstance(Field field, Object testSubject) {
try {
boolean isStatic = isStatic(field.getModifiers());
Object context = isStatic ? null : testSubject;
field.setAccessible(true);
return field.get(context);
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to get instance of field.");
}
}
public static Type[] getTypesForGeneric(Field field) {
ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
return parameterizedType.getActualTypeArguments();
}
}
Refactor it a little bit:
public class MySQLDatabaseConnectionFactory implements DatabaseConnectionFactory {
ConnectionSupplier connectionSupplier = () -> SupplierDriverManager.getConnection();
public void setConnSupplier(ConnectionSupplier supplier) {
this.connectionSupplier = supplier;
}
#Override
public Connection getConnection() {
try {
return connectionSupplier.conn();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
#FunctionalInterface
interface ConnectionSupplier {
Connection conn();
}
}
Then you can use the mockito:
MySQLDatabaseConnectionFactory.ConnectionSupplier connectionSupplier = mock(MySQLDatabaseConnectionFactory.ConnectionSupplier.class);
when(connectionSupplier.conn()).thenReturn(yourMockObject);
yourConnectionFactory.setConnSupplier(connectionSupplier);

JUnits for constructors which uses third party API call

Below mentioned is the class that I need to test:
public class MyClass {
private String key;
public MyClass(Connection con) {
key = ThirdPartyApi.getkey(con);
}
public String getKey() {
return key;
}
}
Now I need to test this constructor, but am unable to mock this Third party API call. And the Test case would be as mentioned below :
public class MyClassTest{
#Test
public void test1(){
MyClass c = new MyClass(dummyconnection);
assertNotNull(c.getKey != null);
}
}
But this case would be giving me an error that ThirdPartyAPI Class is failing as the the connection object is mocked.
So I want to mock this ThirdPartyApi call. Is it possible using Easymock, powermock?
Simple: EasyMock does not support mocking static calls. So you can turn to PowerMock(ito) or JMockit in case you do not want to change your code.
But the better approach would be to understand that using static always leads to tight coupling between your classes, and that you want to make sure that this doesn't affect your ability to unit test your code.
In your case:
public MyClass(Connection con) {
key = ThirdPartyApi.getkey(con);
simply replace that with:
public MyClass(Connection con) {
this (ThirdPartyApi.getkey(con));
}
/** unit testing only */
MyClass(Key key) {
...
And voila, you got a constructor that you can call from your unit test - and now you simply pass a mocked key object. And your tests will no longer execute that static call - because you use the key-taking constructor in all your tests.
But you probably want another test case to make sure that calling the public constructor does what you expect it to do - and that could be to throw an exception because that static call fails.
Beyond that: I fully agree with the comments - the fact that your constructor is doing so much (including static calls) has a certain design smell on it.

How to capture incoming parameters with EasyMock.capture?

I'm testing a class and wanted to monitor calls to a specific method, namely to save the calling parameters for later analysis.
Testing is done with EasyMock, so it was logical to use EasyMock.capture feature. However, the examples that I managed to find do not work for me - I get the following compile error at the line with capture:
expect(T) in EasyMock cannot be applied to (void)
reason: no instance of type variable T exist so that void conforms to T
It would be great if somebody could point out my mistake(s) for me. Below is a code snippet:
import static org.easymock.EasyMock.capture;
import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.junit.Before;
class B {
}
class A {
public void doSomething(B input) {
}
}
public class ATest {
private Capture<B> capturedData;
private A testObject;
#Before
private void setUp() {
capturedData = EasyMock.newCapture(CaptureType.ALL);
testObject = EasyMock.createNiceMock(A.class);
EasyMock
.expect(testObject.doSomething(capture(capturedData)))
.anyTimes();
}
}
Thanks a lot in advance!
Your problem is not related to the capture, but to the return type of your doSomething() method:
Since A.doSomething(B input) is of return type void, you don't expect the method to return anything, thus you cannot use EasyMock.expect() for it. Instead, simply invoke the method and use EasyMock.expectLastCall(), like so:
testObject.doSomething(capture(capturedData));
EasyMock.expectLastCall().anyTimes();
EasyMock.expectLastCall() declares that you expect the last method invocation before expectLastCall() to be executed. You can then handle it just like expect(), e.g. add anyTimes() to it.

Powermock not intercepting new object creation

I am attempting to test a method that creates a new instance of another class that I wish to mock using powermock. My code (simplified) is as follows -
Testing code:
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.easymock.EasyMock.anyObject;
import static org.powermock.api.easymock.PowerMock.*;
#RunWith(PowerMockRunner.class)
#PrepareForTest( { ClassUnderTest.class } )
public class TestForClassUnderTest {
private ClassToBeMocked classToBeMocked;
private ClassUnderTest classUnderTest;
public void testSimple() throws Exception {
classToBeMocked = createMock(ClassToBeMocked.class);
// trying to intercept the constructor
// I *think* this is the root cause of the issue
expectNew(ClassToBeMocked.class, anyObject(), anyObject(), anyObject()).andReturn(classToBeMocked);
classToBeMocked.close();
expectLastCall();
replayAll();
// call to perform the test
classUnderTest.doStuff();
}
}
Code that is being tested:
import ClassToBeMocked;
public class ClassUnderTest {
private ClassToBeMocked classToBeMocked;
public void doStuff() {
classToBeMocked = new ClassToBeMocked("A","B","C");
// doing lots of other things here that I feel are irrelevant
classToBeMocked.close();
}
}
Code that I wish to mock:
public class ClassToBeMocked {
public ClassToBeMocked(String A, String B, String C) {
// irrelevant
}
public close() {
// irrelevant
}
}
The error I get is as below:
java.lang.ExceptionInInitializerError
at ....more inner details of where this goes into
at ClassToBeMocked.close
at ClassUnderTest.doStuff
at TestForClassUnderTest.test.unit.testSimple
Caused by: java.lang.NullPointerException
PowerMock version:1.4.5
EasyMock version: 3.1
PS: I have stripped down the code to bare minimums, only showing the details of the mocking library, let me know if you think my other code is somehow interfering and I can give more details on the bits you think are important to show. Any links to other examples doing this may even help.
I realized that the reason this wasn't working was because I was extending another class. I had
#RunWith(PowerMockRunner.class)
#PrepareForTest( { ClassUnderTest.class } )
public class TestForClassUnderTest extends AnotherClass {
}
as soon as I removed the extends, it worked. Not sure if its just not able to extend another class with powermock or due to AnotherClass, but removing it worked for me
whenever you wish to mock a new instance of any class, you should be doing like this
Powermock.expectNew(ClassYouWishToMock.class).andReturn(whateverYouWantToReturn).anyTimes();
Powermock.replayAll();
this will return 'whateverYouWantToReturn' whener new is called on this class.
but whenever you want to mock a instance variable, you should be using Whitebox feature of easymock.
have a look at following Example
Class A{
private B b;
}
to mock this my test class will look something like this
...//other powermock, easymock class level annotations
#PrepareForTest(B.class)
class ATest{
Whitebox.setInternalState(B.class,b,whateverValueYouWantYourMockedObjectToReflect);
}
here 'b' passed in parameter, is the variable name you want to mock.
Good Luck!

Singleton and unit testing

The Effective Java has the following statement on unit testing singletons
Making a class a singleton can make it difficult to test its clients, as it’s impossible to substitute a mock implementation for a singleton unless it implements an interface that serves as its type.
Can anyone explain the why this is so ?
You could use reflection to reset your singleton object to prevent tests from affecting each other.
#Before
public void resetSingleton() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field instance = MySingleton.class.getDeclaredField("instance");
instance.setAccessible(true);
instance.set(null, null);
}
Ref: unit-testing-singletons
The problem isn't testing singletons themselves; the book is saying that if a class you are trying to test depends on a singleton, then you will likely have problems.
Unless, that is, you (1) make the singleton implement an interface, and (2) inject the singleton to your class using that interface.
For example, singletons are typically instantiated directly like this:
public class MyClass
{
private MySingleton __s = MySingleton.getInstance() ;
...
}
MyClass may now be very difficult to automatedly test. For example, as #Boris Pavlović notes in his answer, if the singleton's behaviour is based on the system time, your tests are now also dependent on the system time, and you may not be able to test cases that, say, depend on the day of the week.
However, if your singleton "implements an interface that serves as its type" then you can still use a singleton implementation of that interface, so long as you pass it in:
public class SomeSingleton
implements SomeInterface
{
...
}
public class MyClass
{
private SomeInterface __s ;
public MyClass( SomeInterface s )
{
__s = s ;
}
...
}
...
MyClass m = new MyClass( SomeSingleton.getInstance() ) ;
From the perspective of testing MyClass you now don't care if SomeSingleton is singleton or not: you can also pass in any other implementation you want, including the singleton implementation, but most likely you'll use a mock of some sort which you control from your tests.
BTW, this is NOT the way to do it:
public class MyClass
{
private SomeInterface __s = SomeSingleton.getInstance() ;
public MyClass()
{
}
...
}
That still works out the same at run-time, but for testing you are now again dependent on SomeSingleton.
Mocks require interfaces, because what you're doing is replacing the real underlying behavior with an imposter that mimics what you need for the test. Since the client only deals with an interface reference type, it doesn't need to know what the implementation is.
You can't mock a concrete class without an interface, because you can't replace the behavior without the test client knowing about it. It's a completely new class in that case.
It's true for all classes, Singleton or not.
I think it actually depends on the implementation of the singleton access pattern.
For example
MySingleton.getInstance()
Might be very dificult to test while
MySingletonFactory mySingletonFactory = ...
mySingletonFactory.getInstance() //this returns a MySingleton instance or even a subclass
Doesn't provide any information about the fact that its using a singleton. So you can freely replace your factory.
NOTE: a singleton is defined by being only one instance of that class in an application, however the way it's obtained or stored doesn't have to be through static means.
It's oh so simple.
In unit-testing, you want to isolate your SUT (the class you're testing).
You don't want to test a bunch of classes, because that would defeat the purpose of unit-testing.
But not all classes do everything on their own, right? Most classes use other classes to do their work, and they kind of mediate between other classes, and add a bit of their own, to get the final result.
The point is - you don't care about how the classes your SUT depends on work. You care how your SUT works with those classes. That's why you stub or mock the classes your SUT needs. And you can use those mocks because you can pass them in as constructor parameters for your SUT.
With singletons - the bad thing is that the getInstance() method is globally accessible. That means that you usually call it from within a class, instead of depending on an interface you can later mock. That's why it's impossible to replace it when you want to test your SUT.
The solution is not to use the sneaky public static MySingleton getInstance() method, but to depend on an interface your class needs to work with. Do that, and you can pass in test doubles whenever you need to.
Singleton objects are created without any control from the outside. In one of the other chapters of the same book Bloch suggests using enums as default Singleton implementation. Let's see an example
public enum Day {
MON(2), TUE(3), WED(4), THU(5), FRI(6), SAT(7), SUN(1);
private final int index;
private Day(int index) {
this.index = index;
}
public boolean isToday() {
return index == new GregorianCalendar().get(Calendar.DAY_OF_WEEK);
}
}
Let's say we have a code that should be executed only on weekends:
public void leisure() {
if (Day.SAT.isToday() || Day.SUN.isToday()) {
haveSomeFun();
return;
}
doSomeWork();
}
Testing leisure method is going to be pretty hard. Its execution is going to be dependent on the day when it is executed. If it executes on a weekday doSomeWork() will be invoked and on weekends haveSomeFun().
For this case we would need to use some heavy tools like PowerMock to intercept the GregorianCalendar constructor, return a mock which will return an index corresponding to a weekday or weekend in two test cases testing both execution paths of the leisure method.
it’s impossible to substitute a mock implementation for a singleton
This is not true. You can subclass your singleton and setter inject a mock. Alternatively, you can use PowerMock to mock static methods. However the need to mock singletons can be symptomatic of poor design.
The real problem is Singletons when abused turn into dependency magnets. Since they are accessible everywhere, it can appear more convenient to put the functions you need in them rather than delegating to an appropriate class, especially for programmers new to OOP.
The testability problem is now you have a bunch of Singletons that are accessed by your object under test. Even though the object probably only uses a small fraction of methods in the Singletons, you still need to mock each Singleton and figure out which methods are depended on. Singletons with a static state (Monostate pattern) are even worse because you can have to figure out which interactions between objects are affected by the Singleton's state.
Used carefully, Singletons and testability can occur together. For instance, in absence of a DI framework, you can use Singletons as your Factories and ServiceLocators, which you can setter inject to create a fake service layer for your end-to-end tests.
It is possible, see the example
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.lang.reflect.Field;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class DriverSnapshotHandlerTest {
private static final String MOCKED_URL = "MockedURL";
private FormatterService formatter;
#SuppressWarnings("javadoc")
#Before
public void setUp() {
formatter = mock(FormatterService.class);
setMock(formatter);
when(formatter.formatTachoIcon()).thenReturn(MOCKED_URL);
}
/**
* Remove the mocked instance from the class. It is important, because other tests will be confused with the mocked instance.
* #throws Exception if the instance could not be accessible
*/
#After
public void resetSingleton() throws Exception {
Field instance = FormatterService.class.getDeclaredField("instance");
instance.setAccessible(true);
instance.set(null, null);
}
/**
* Set a mock to the {#link FormatterService} instance
* Throws {#link RuntimeException} in case if reflection failed, see a {#link Field#set(Object, Object)} method description.
* #param mock the mock to be inserted to a class
*/
private void setMock(FormatterService mock) {
Field instance;
try {
instance = FormatterService.class.getDeclaredField("instance");
instance.setAccessible(true);
instance.set(instance, mock);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Test method for {#link com.example.DriverSnapshotHandler#getImageURL()}.
*/
#Test
public void testFormatterServiceIsCalled() {
DriverSnapshotHandler handler = new DriverSnapshotHandler();
String url = handler.getImageURL();
verify(formatter, atLeastOnce()).formatTachoIcon();
assertEquals(MOCKED_URL, url);
}
}
Use PowerMock to mock Singleton class (SingletonClassHelper) instance and non-static method (nonStaticMethod) which is called in task.execute().
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#PrepareForTest({ SingletonClassHelper.class })
#RunWith(PowerMockRunner.class)
public class ClassToTest {
#InjectMocks
Task task;
private static final String TEST_PAYLOAD = "data";
private SingletonClassHelper singletonClassHelper;
#Before
public void setUp() {
PowerMockito.mockStatic(SingletonClassHelper.class);
singletonClassHelper = Mockito.mock(SingletonClassHelper.class);
when(SingletonClassHelper.getInstance()).thenReturn(singletonClassHelper);
}
#Test
public void test() {
when(singletonClassHelper.nonStaticMethod(parameterA, parameterB, ...)).thenReturn(TEST_PAYLOAD);
task.execute();
}
}
durian-globals does lazy double-locked initialization of singletons, but also has a simple test-only API which allows you to replace the implementation for unit testing.
As far as I know, a class implementing a Singleton cannot be extended (superclass constructor is always called implicitly and the constructor in a Singleton is private). If you want to mock a class you have to extend the class. As you see in this case it wouldn't be possible.
The problem with singletons (and also with static methods) is that it makes it hard to replace the actual code with a mocked implementation.
For example consider the following code
public class TestMe() {
public String foo(String data) {
boolean isFeatureFlag = MySingletonConfig.getInstance().getFeatureFlag();
if (isFeatureFlag)
// do somethine with data
else
// do something else with the data
return result;
}
}
It is not easy to write a unit test for the foo method and verifying the correct behavior is performed.
This is because you can't easily change the return value of getFeatureFlag.
The same problem exists for static methods - it's not easy to replace the actual target class method with a mock behavior.
Sure, there are workarounds like powermock, or dependency injection to the method, or reflection in tests.
But it is much better not to use singletons in the first place
Below there is the solution I had to adopt with some immutable Kotlin singleton to test them
Suppose you have a singleton class like this:
class MySingleton private constructor(
{your dependencies}
) {
companion object {
#JvmStatic
private var INSTANCE: MySingleton? = null
#JvmStatic
fun getInstance(): MySingleton {
return INSTANCE ?: synchronized(this) {
INSTANCE ?: MySingleton(
{your dependencies}
).also {
INSTANCE = it
}
}
}
}
}
You can do this in your kotlin junit tests:
#After
fun after() {
val instance = MySingleton.Companion::class.memberProperties.find {
it.name == "INSTANCE"
}
instance!!.isAccessible = true
instance.javaField!!.set(null, null)
}
You just need to add the kotlin-reflect artifact to your dependencies

Categories