JMockit Dependency Constructor - java

I am looking to mock out a Domain Dependency while I test a Service Class, using JMockit. The problem is, that the Domain object is instantiated in one of the Service's methods, and the Domain constructor used, has parameters.
Domain Class:
package com.example;
public class DomainClass {
String str;
public DomainClass(String s) {
str=s;
}
public String domainMethod() {
return str;
}
}
Service Class
package com.example;
public class ServiceClass {
public String serviceMethod() {
return new DomainClass("original").domainMethod();
}
}
How do I mock out the DomainClass that the ServiceClass is using?
Note: I am not looking to change the Domain or Service classes. (I realize that this code is is trivial and could be written better, but it is just a simple example of more complex code.)
Test Class (Final Answer)
package com.example;
import org.testng.*;
import org.testng.annotations.*;
import mockit.*;
public class TestClass {
#Mocked DomainClass domainClass;
#Test
public void testMethod() {
new Expectations() {{
new DomainClass("original").domainMethod(); result = "dummy";
}};
String ss = new ServiceClass().serviceMethod();
System.out.println(ss);
Assert.assertEquals(ss, "dummy");
}
}

The JMockit documentation should answer that.
Anyway, to mock a class, simply use #Mocked DomainClass (as mock field or test method parameter).
BTW, having new DomainClass("original").domainMethod() is not "bad design" (on the contrary, turning it into a singleton - injected or not - would be). However, mocking such classes may very well be a bad idea; always prefer not mocking.

Related

How to test a service or do it right mock? Java11, Spock Framework

Colleagues, I welcome you all! Tell me how to decide, or how to act. (Java11, SpringBoot, testing - Spock Framework) I need to write a test that will test a class method, the whole problem is that the method of the class under test calls another service through inheritance, which is not declared in the class under test, but in its abstract ancestor. How to test such a story? If this service were declared in the class under test itself, then everything is clear, I would create a mock in the test and pass it to the constructor, but what if this service is located at the ancestor? I am attaching an example code below.
// The class to be tested
#Service
public class ServiceForTest extends AbstractComponent{
public String methodForTest (String s) {
return someService.generateString(s);
}
}
//An abstract class from which the tested one is inherited and which contains the service
public class AbstractComponent {
#Autowired
protected SomeService someService;
}
public interface SomeService {
String generateString(String s);
}
#Service
public class SomeServiceImpl implements SomeService{
#Override
public String generateString(String s) {
return s;
}
}
And below is an example of what I would do if the service was in the class being tested
//TestClass
#Service
public class ServiceForTest extends AbstractComponent{
final SomeService someService;
public ServiceForTest(SomeService someService) {
this.someService = someService;
}
public String methodForTest (String s) {
return someService.generateString(s);
}
}
class test groovy, Spock Framework
class ServiceForTestTest extends Specification {
ServiceForTest serviceForTest
void setup(){
SomeService someServiceMock = Mock(SomeService)
someServiceMock.generateString("TEST") >> "TEST"
serviceForTest = new ServiceForTest(someServiceMock)
}
def "Test for return current value"(){
when:
def methodForTest = serviceForTest.methodForTest("TEST")
then:
methodForTest == "TEST"
}
}
You use #Autowired, i.e. some kind of dependency injection framework such as Spring or Java EE CDI. Those frameworks have testing support. Specifically for Spring testing, Spock has a Spring module which you can use. I am not a Spring user, so I cannot tell you how to exactly do that, but the documentation is pretty good.
As a general answer, even without any framework support you can test this easily, if you follow the convention to put the test into the same package as the class under test. Because the field you want to inject a mock into is protected, it means for the JVM that all subclasses, but also other classes in the same package have access to it. I.e., you can simply set the value:
serviceForTest = new ServiceForTest()
serviceForTest.someService = someServiceMock
Or, more elegantly using a Groovy-style constructor which implicitly sets field values:
serviceForTest = new ServiceForTest(someService: someServiceMock)
Generally, I recommend constructor or setter injection rather than relying on field injection (especially when fields are private), because then with regard to testability you have a strict dependency to your DI framework and cannot easily write unit tests. So if you can refactor, I recommend you to do it. You just noticed that testing such things can be kind of a headache, unless you have a way out like in this particular case with the protected field. But that is not so super refactoring-friendly.

Mockito spy is calling the actual class instead of setting the mock when using Guice's Transactional

This question is similar to this one but the solution is not working. There is a problem with mockito and Guice
package mock
import com.google.inject.persist.Transactional;
import lombok.NonNull;
import java.util.ArrayList;
import java.util.List;
public class SomeClass {
public int A() {
ArrayList<Object> objects = new ArrayList<>();
return this.B(objects);
}
#Transactional
public int B(#NonNull List<Object> someList) {
return 1;
}
}
I want to unit test A and check the parameters that calls B with. Hence I do:
#Test
void someTest() {
SomeClass obj = GuiceConfig.getInjector()
.getInstance(SomeClass.class);
SomeClass objSpy = Mockito.spy(obj);
ArgumentCaptor<List<Object>> captor =
ArgumentCaptor
.forClass(List.class);
// when(objSpy.B(captor.capture())).thenReturn(1);
doReturn(0).when(objSpy).B(captor.capture());
}
Instead of mocking B, it is calling the actual implementation of B with null and raising a NPE. In the aforementioned question it was suggested that using doReturn would fix this issue, because using when(objSpy.B(captor.capture)).thenReturn(0) would execute the underlying method. Note, if I don't use #Transactional then it works (where as when call fails)

Mockito mocks locally final class but fails in Jenkins

I have written some unit tests for a static method. The static method takes only one argument. The argument's type is a final class. In terms of code:
public class Utility {
public static Optional<String> getName(Customer customer) {
// method's body.
}
}
public final class Customer {
// class definition
}
So for the Utility class I have created a test class UtilityTests in which I have written tests for this method, getName. The unit testing framework is TestNG and the mocking library that is used is Mockito. So a typical test has the following structure:
public class UtilityTests {
#Test
public void getNameTest() {
// Arrange
Customer customerMock = Mockito.mock(Customer.class);
Mockito.when(...).thenReturn(...);
// Act
Optional<String> name = Utility.getName(customerMock);
// Assert
Assert.assertTrue(...);
}
}
What is the problem ?
Whereas the tests run successfully locally, inside IntelliJ, they fail on Jenkins (when I push my code in the remote branch, a build is triggered and unit tests run at the end). The error message is sth like the following:
org.mockito.exceptions.base.MockitoException: Cannot mock/spy class
com.packagename.Customer Mockito
cannot mock/spy because :
- final class
What I tried ?
I searched a bit, in order to find a solution but I didn't make it. I note here that I am not allowed to change the fact that Customer is a final class. In addition to this, I would like if possible to not change it's design at all (e.g. creating an interface, that would hold the methods that I want to mock and state that the Customer class implements that interface, as correctly Jose pointed out in his comment). The thing that I tried is the second option mentioned at mockito-final. Despite the fact that this fixed the problem, it brake some other unit tests :(, that cannot be fixed in none apparent way.
Questions
So here are the two questions I have:
How that is possible in the first place ? Shouldn't the test fail both locally and in Jenkins ?
How this can be fixed based in the constraints I mentioned above ?
Thanks in advance for any help.
An alternative approach would be to use the 'method to class' pattern.
Move the methods out of the customer class into another class/classes, say CustomerSomething eg/CustomerFinances (or whatever it's responsibility is).
Add a constructor to Customer.
Now you don't need to mock Customer, just the CustomerSomething class! You may not need to mock that either if it has no external dependencies.
Here's a good blog on the topic: https://simpleprogrammer.com/back-to-basics-mock-eliminating-patterns/
How that is possible in the first place? Shouldn't the test fail both locally and in Jenkins ?
It's obviously a kind of env-specifics. The only question is - how to determine the cause of difference.
I'd suggest you to check org.mockito.internal.util.MockUtil#typeMockabilityOf method and compare, what mockMaker is actually used in both environments and why.
If mockMaker is the same - compare loaded classes IDE-Client vs Jenkins-Client - do they have any difference on the time of test execution.
How this can be fixed based in the constraints I mentioned above?
The following code is written in assumption of OpenJDK 12 and Mockito 2.28.2, but I believe you can adjust it to any actually used version.
public class UtilityTest {
#Rule
public InlineMocksRule inlineMocksRule = new InlineMocksRule();
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Test
public void testFinalClass() {
// Given
String testName = "Ainz Ooal Gown";
Client client = Mockito.mock(Client.class);
Mockito.when(client.getName()).thenReturn(testName);
// When
String name = Utility.getName(client).orElseThrow();
// Then
assertEquals(testName, name);
}
static final class Client {
final String getName() {
return "text";
}
}
static final class Utility {
static Optional<String> getName(Client client) {
return Optional.ofNullable(client).map(Client::getName);
}
}
}
With a separate rule for inline mocks:
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.mockito.internal.configuration.plugins.Plugins;
import org.mockito.internal.util.MockUtil;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class InlineMocksRule implements TestRule {
private static Field MOCK_MAKER_FIELD;
static {
try {
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Field.class, MethodHandles.lookup());
VarHandle modifiers = lookup.findVarHandle(Field.class, "modifiers", int.class);
MOCK_MAKER_FIELD = MockUtil.class.getDeclaredField("mockMaker");
MOCK_MAKER_FIELD.setAccessible(true);
int mods = MOCK_MAKER_FIELD.getModifiers();
if (Modifier.isFinal(mods)) {
modifiers.set(MOCK_MAKER_FIELD, mods & ~Modifier.FINAL);
}
} catch (IllegalAccessException | NoSuchFieldException ex) {
throw new RuntimeException(ex);
}
}
#Override
public Statement apply(Statement base, Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
Object oldMaker = MOCK_MAKER_FIELD.get(null);
MOCK_MAKER_FIELD.set(null, Plugins.getPlugins().getInlineMockMaker());
try {
base.evaluate();
} finally {
MOCK_MAKER_FIELD.set(null, oldMaker);
}
}
};
}
}
Make sure you run the test with the same arguments. Check if your intellij run configurations match the jenkins. https://www.jetbrains.com/help/idea/creating-and-editing-run-debug-configurations.html. You can try to run test on local machine with the same arguments as on jenkins(from terminal), if it will fail that means the problem is in arguments

Mock inner methods using Mockito

I am new to Mockito.
I am trying to write jnuit for a service by mocking the db interactions:
I have following classes (just representative of actual classes)
public class TestService{
public Response getTestList(String type){
list = getListbyType(type);
return response.entity(list);
}
private List getListbyType(String type){
...
..
TestDAO testdao = new Testdao(sqlconn);
list = testdao.getListfromDB(type)
return list;
}
}
And my test class is something like
public class TestServiceTest{
#InjectMocks
private TestService testService = new TestService();
#Test
public void getTestListTest(){
List testlist = new List();
tetslist.add("test1");
TestDAO testdaomock = mock(TestDAO);
when(testdaomock.getListfromDB("test")).thenreturn(list);
list = testService.getTestList(test);
}
}
But when I run this test, it still invokes the actual DB call and retrieves the values from db and not the mocked values, should I mock sql connection and non default constructor? I am clueless.
-- UPDATE
As people have suggested, I moved DAO instantiation to my service constructor and also used Spy, But still my actual DB call is invoked instead of the mock call.
Your problem is with the following statement:
TestDAO testdao = new Testdao(sqlconn);
The instance of TestDAO you got from mock() is not the instance used in testdao.getListfromDB(type) that follows new
In order to successfully mock, you need to apply the inversion of dependencies throughout. That means new must only show up in classes you don't intend to test, such as simplistic factories or Spring config files.
[Update]
If proper IOC is not an option, you can introduce a method that allocates DAO and then spy() it. The method would have to be package-private. This is described here.
Another option would be to add a package-private constructor taking testdao as argument and expressing your default constructor in the terms of that constructor.
In case you can't change the TestService class (legacy code) there is a possiblity to mock the new instance with PowerMockito (https://github.com/jayway/powermock). This uses a own junit runner (PowerMockRunner) that allows the byte-code manipulation.
Here an example for your code:
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
public class TestServiceTest {
#Mock
TestDAO testDaoMock;
#Test
public void test() throws Exception {
List<String> testlist = new ArrayList<>();
testlist.add("test1");
when(testDaoMock.getListfromDB(anyString())).thenReturn(testlist);
PowerMockito.whenNew(TestDAO.class).withAnyArguments().thenReturn(testDaoMock);
TestService testService = new TestService();
Response actualResponse = testService.getTestList("testType");
assertEquals(expectedResponse, actualResponse);
}
}
You will need to add powermock-api-mockito and powermock-module-junit4 to your dependcies.

How to test a Jersey rest service using mock objects

I have developed a rest service using Jersey. Now I want to write some integration tests for this web service but since not every class being used from the web service is already implemented I need to mock some of them. For example I have the following class:
public class A {
private String getWeather() {
return null;
}
}
My web service looks like this :
#Path("/myresource")
public class MyResource {
#GET
#Produces("text/plain")
public String getIt() {
A a = new A();
return a.getWeather();
}
}
The problem is that the getWeather function is not ready so I need to mock the return value for this function. But for the integration test where I issue a rest call I don't know how to do that.
Are there any ideas?
To make your design decoupled from A you should pass it in as a parameter to MyResource. Then you can easily mock it by hand or with mockito. With constructor injection it would look like this:
#Path("/myresource")
public class MyResource {
private A a;
public MyResource(A a) {
this.a = a;
}
#GET
#Produces("text/plain")
public String getIt() {
return a.getWeather();
}
}
and you can test it with
#Test
public void shouldGetIt() {
A a = mock(A.class);
when(a.getWeather()).thenReturn("sunny!");
MyResource r = new MyResource(a);
assertThat(r.getIt(), is("sunny!));
}
This makes your design decoupled. MyResource no longer depends on A directly but on anything that looks lik an A. Another benefit is that mockito doesn't mess with you class files. It is your code that is tested - not something that has been generated on the fly.
Many consider injection by constructor to be a bit old school. I am old so I like it.... With spring (a framework I don't recommend that you pick up) you can autowire variables like so:
#Autowire
private A a;
and you don't need the constructor at all. Spring will find a the only implementation of A and insert it in this variable. I prefer explicit programming so I would chose constructor injection any day.
You may be able to achieve this using Power Mockito (https://code.google.com/p/powermock/wiki/MockitoUsage)
#RunWith(PowerMockRunner.class)
#PrepareForTest({ MyResource.class })
public class MyResourceTest {
#Test
public void testGetIt()() {
MyResource mr = new MyResource();
//Setup mock
A mockA = PowerMockito.mock(A.class);
String mockReturn = "Some String";
//Stub new A() with your mock
PowerMockito.whenNew(A.class).withAnyArguments().thenReturn(mockA);
PowerMockito.doReturn(mockReturn).when(mockA).getWeather();
String ret = mr.getIt();
//asserts go here
}
}
Note that you can mock a local variable creation using PowerMockito's whenNew - this should take care of your concern for A a = new A() code in getIt() method.

Categories

Resources