My question is not this question.
I want to mock private wrapper fields like Integer and String.
Also, these fields are in an abstract super class.
public abstract class SuperSample
{
private Integer var1;
private String var2;
private Service service;
pubic boolean foo()
{
int a = service.doStuff(var1, var2);
return subMethod(a);
}
protected abstract boolean subMethod(int var);
public void setVar1(Integer var1)
{
this.va1 = var1;
}
public Integer getVar1()
{
return var1;
}
public void setVar2(String var2)
{
this.var2 = var2;
}
public String getVar2()
{
return var2;
}
public void setService(Service service)
{
this.service = service;
}
public String getService()
{
return service;
}
}
public class Sample extends SuperSample
{
protected boolean subMethod(int var)
{
return var%2==0?true:false;
}
}
Spring.xml -
<bean id="superSample" class="SuperSample" abstract="true">
<property name="var1" value="2" />
<property name="var2" value="cool" />
</bean>
<bean id="sample" class="Sample" >
<property name="service" ref="service" />
</bean>
In my junit I can't mock or spy var1 or var2. On spying/mocking var1, var2 I get the error:
org.mockito.exceptions.base.MockitoException: Cannot mock/spy class
java.lang.Integer Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
I want to mock the line -
service.doStuff(var1, var2)
with something like-
#UnitTest
public class SampleTest
{
#Mock
private Service service;
private Integer var1 = 2
private String var2 = "cool";
#InjectMocks
private Sample sample;
#Test
public void test()
{
MockitoAnnotations.initMocks(this);
Mockito.when(service.doStuff(var1, var2)).thenReturn(5);
}
}
You can simply inject the values yourself and then remove the #InjectMocks annotation. This can best be done in a setup method annotated with #Before so it gets executed for every test.
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
sample = new Sample();
sample.setVar1(1234);
sample.setVar2("5678");
sample.setService(service);
}
Based on currently shown example the mock can be injected via the set member
#UnitTest
public class SampleTest {
#Mock
private Service service;
private Integer var1 = 2
private String var2 = "cool";
#Test
public void test() {
//Arrange
MockitoAnnotations.initMocks(this);
Sample sample = new Sample();
sample.setService(service);
sample.setVar1(var1);
sample.setVar2(var2);
Mockito.when(service.doStuff(var1, var2)).thenReturn(5);
//Act
boolean actual = sample.foo();
//Assert
//...
}
}
Ideally, the more SOLID design approach would be to refactor the subject class to use explicit dependency principle via constructor injection
public class Sample extends SuperSample {
public Sample(Service service) {
super.setService(service);
}
protected boolean subMethod(int var) {
return var%2==0?true:false;
}
}
Allowing any explicit dependencies to be injected
#UnitTest
public class SampleTest {
#Mock
private Service service;
private Integer var1 = 2
private String var2 = "cool";
#InjectMocks
private Sample sample;
#Test
public void test() {
//Arrange
MockitoAnnotations.initMocks(this);
sample.setVar1(var1);
sample.setVar2(var2);
Mockito.when(service.doStuff(var1, var2)).thenReturn(5);
//Act
boolean actual = sample.foo();
//Assert
//...
}
}
Here you go, we created a JUnit extension to solve this precise problem.
https://github.com/exabrial/mockito-object-injection
Related
I have been searching for a while and I can't find a solution for this. I need to mock a class that is used in the #PostConstruct of another class. My classes are like this:
#Component
class A {
private final B b;
private String s;
public A(B b) {this.b = b;}
#PostConstruct
public void postConstruct() {
s = b.get().getString().toUpperCase();
}
}
#Component
class B {
private final C c;
public B(C c) {this.c = c;}
public C get() {return c;}
}
#Component
class C {
public C() throws Exception {throw new Exception();}
String getString() {return "C";}
}
Now I create the test that fails because the constructor of C fails:
#SpringBootTest
class DemoApplicationTests {
#Autowired A a;
#Test
public void canLoadContext() {
assertThat(a).isNotNull();
}
}
So I try to mock the C class:
#SpringBootTest
class DemoApplicationTests {
#MockBean
static C c;
#Autowired
A a;
#BeforeEach
public void beforeEach() {
when(c.getString())
.thenReturn("C_mocked");
}
#Test
public void canLoadContext() {
assertThat(a).isNotNull();
}
}
But this way it fails with a NPE in the line s = b.get().getString().toUpperCase(); because the C object in b is not the same that I have mocked with #MockBean. When getString() is called, it returns null and we get a NPE when calling .toUpperCase().
I have also tried to overwrite the mock like this:
#Configuration
#AutoConfigureBefore
static class TestContext {
#Primary
public C c() {
return when(mock(C.class).getString())
.thenReturn("C_mocked").getMock();
}
}
But in this case I get this error:
No qualifying bean of type 'com.example.demo.A' available: expected at
least 1 bean which qualifies as autowire candidate.
Could please somebody help out with this?
I don't know how to mark it as duplicate. But please take a look of this https://stackoverflow.com/a/58517289/11538031
The solution remains like this:
#Component
class A {
private final B b;
private String s;
public A(B b) {this.b = b;}
#PostConstruct
public void postConstruct() {
s = b.get().getString().toUpperCase();
}
}
#Component
class B {
private final C c;
public B(C c) {this.c = c;}
public C get() {return c;}
}
#Component
class C {
public C() throws Exception {throw new Exception();}
String getString() {return "C";}
}
#SpringBootTest
class DemoApplicationTests {
#Autowired
A a;
#Test
public void canLoadContext() {
assertThat(a).isNotNull();
}
#TestConfiguration
public static class TestContext {
#Bean
#Primary
public C c() {
return when(mock(C.class).getString())
.thenReturn("C_mocked").getMock();
}
}
}
I have a POJO class:
#Data #Document
public class RoomPreferences{
private TypeEnum roomType;
private BigDecimal minLen;
private BigDecimal maxLen;
private List<BigDecimal> defaultPrices;
}
I want to populate a RoomPreferences object at test and I am using Mockito, but my RoomPreferences object's fields are always null.
public class TestingClass {
#Mock private RoomPreferences roomPreferences;
#InjectMocks public RoomServiceImpl roomService;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
when(roomPreferences.getMinLen()).thenReturn(BigDecimal.valueOf(10));
...
}
}
What I read out of this testing class:
public class TestingClass {
#Mock private RoomPreferences roomPreferences;
#InjectMocks public RoomServiceImpl roomService;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
when(roomPreferences.getMinLen()).thenReturn(BigDecimal.valueOf(10));
...
}
}
is that roomService of type RoomServiceImpl has an attribute of type RoomPreferences. And this attribute will be injected with the mocked object "roomPreferences".
The mocked object won't be populated with any value of the real class.
What you do is define what the mock should do when a method (as in the real class) is called on it:
when(roomPreferences.getMinLen()).thenReturn(BigDecimal.valueOf(10));
If you wan to assing a value to a property then don't mock the class and use the real class instead.
I am guessing that the problem you are facing is setting the RoomPreferences attribute in the roomService object. If that is the case you should add that class to the question.
Using Powermock 2.0.7 (powermock-api-mockito2, powermock-core, powermock-module-junit4) and mockito-core (3.3.3). I thought I had created a comparable test scenario in a separate project (which worked), but something else must be missing.
Library class to be mocked:
public class CommonConstants {
private ConfigurationDataImpl configurationData;
private static Properties sysProperties;
private static Map<String, String> sysPermissions;
public CommonConstants(ConfigurationDataImpl configurationData) {
this.configurationData = configurationData;
}
public void init() {
sysProperties = this.configurationData.getSysParams();
sysPermissions = this.configurationData.getSysPermissions();
}
public static String getSysProperties(String key) {
return sysProperties.getProperty(key);
}
public static String getSysPermissions(String key) {
return (String)sysPermissions.get(key);
}
}
In my test, I have:
#RunWith(PowerMockRunner.class)
#PrepareForTest({CommonConstants.class}) <==== class that evidently is not modified!
class MyServiceTest {
public MyServiceTest() {}
#Mock
private MyDao myDao;
#InjectMocks
private MyService myService;
#Test
void retrieveUsers() {
RequestPayload rp = returnPayload();
PowerMockito.mockStatic(CommonConstants.class); <==== EXCEPTION
when(CommonConstants.getSysProperties(HOURS_TO_REGISTER)).thenReturn("24");
...
In the service code, I have:
#Service
#Slf4j
public class MyService {
MyDao myDao;
public MyService(MyDao myDao) {
this.myDao = myDao;
}
public UserListResponse retrieveUsers(RequestPayload requestPayload, String customer) {
List<User> users = myDao.getPtdUsers(queryParams, customer, totalRecords);
int hoursToExpire = Integer.parseInt(CommonConstants.getSysProperties(HOURS__TO_REGISTER));
...
Am I leaving out something? All help appreciated.
I'm new to TDD and mockito aswell, I'm trying to inject mocks into a class to perform a unit test, the class instantiate its dependencies inside a method depending on some validations, I got an error
test class/method
//Its interface
public interface UserService {
public Debt getCustomerDebt(String id);
}
//validator method
public static boolean isValidId(String id){
if(id != null && !id.isEmpty() && !id.trim().equals("")){
return true;
}
return false;
}
public class UserServiceImpl implements UserService {
private Repository repo;
private WSDLCustomerDebt wsdlCostumerDebt;
public static final int USER_EXIST = 1;
public static final int USER_DOESNOT_EXIST = 0;
public UserServiceImpl(){
}
public Debt getCustomerDebt(String id) {
if(ValidatorHelper.isValidId(id)){
repo = new RepositoryImpl();
int exist = repo.getCustomer(id);
if(exist==USER_EXIST){
wsdlCostumerDebt = new WSDLCustomerDebtImpl();
List<Date> meses = wsdlCostumerDebt.obtenerMeses(id);
if(meses.size()>0){
int totalDebt = 0;
for (Date mes : meses){
totalDebt += wsdlCostumerDebt.obtenerDeuda(mes, id);
}
return new Debt(id, BigDecimal.valueOf(totalDebt));
}else{
return new Debt(id, BigDecimal.valueOf(0));
}
}
}
return null;
}
}
mocked class repositoryimpl
public class RepositoryImpl implements Repository {
public int getCustomer(String id) {
int y = Integer.valueOf(1);
return y;
}
}
wsdl mocked class
//Interface
public interface WSDLCustomerDebt {
public List<Date> obtenerMeses(String customerId);
public Integer obtenerDeuda(Date month, String customerId);
}
public class WSDLCustomerDebtImpl implements WSDLCustomerDebt {
public List<Date> obtenerMeses(String customerId) {
return null;
}
public Integer obtenerDeuda(Date month, String customerId) {
Integer y = Integer.valueOf(11);
return y;
}
}
domain class debt
public class Debt {
private String id;
private BigDecimal debt;
public Debt(String id, BigDecimal debt) {
super();
this.id = id;
this.debt = debt;
}
//Getters and setters ....
}
finally test class
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
public class UserServiceImplTest {
#Mock
private Repository repo;
#Mock
private WSDLCustomerDebt wsdlCustomerDebt;
#InjectMocks
private UserServiceImpl userService;
#Before
public void init(){
//repo=Mockito.mock(Repository.class);
//when(wsdlcustomer.obtenerDeuda(D, customerId))
MockitoAnnotations.initMocks(this);
}
#Test
public void noExistingCustomer(){
//Given:
String id = "123";
//When:
Mockito.when(repo.getCustomer(id)).thenReturn(0);
Debt debt = userService.getCustomerDebt(id);
Mockito.verify(repo.getCustomer(Mockito.any(String.class)));
//Then:
assertNull(debt);
}
}
this is the error I'm getting and I'm trying to avoid using a constructor or any getter/setter and to receive the mocks via parameters, maybe it could be caused by a dummy error but at this point I do not know what I'm doing wrong, in fact i think the problem occurs because of the return statement in mocked classes. I'm using mockito version 1.9.5 btw
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type Integer and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
verify(mock).someMethod();
verify(mock, times(10)).someMethod();
verify(mock, atLeastOnce()).someMethod();
at com.i2btech.poctest.UserServiceImplTest.noExistingCustomer(UserServiceImplTest.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
First of all, your service doesn't use the mock you're injecting, since it creates a new one when you call the method. The repo should be an argument of the service constructor.
Second, the proper syntax to verify that a method of a mock has been called is not
verify(mock.method())
but
verify(mock).method()
(as the error message clearly says).
So, the line
Mockito.verify(repo.getCustomer(Mockito.any(String.class)))
must be replaced by
Mockito.verify(repo).getCustomer(Mockito.any(String.class))
I have the following EJB's:
PersonService.java
#Local
public interface PersonService {
long countPersons();
}
PersonServiceImpl.java
#Stateless
public class PersonServiceImpl implements PersonService {
#EJB
private RemotePersonService remotePersonService;
#Override
public long countPersons() {
return remotePersonService.getAllPersons().size();
}
}
RemotePersonService.java
#Local
public interface RemotePersonService {
List<Person> getAllPersons();
}
RemotePersonServiceImpl.Java
#Stateless
public class RemotePersonServiceImpl {
#Override
public List<Person> getAllPersons() {
// Here, I normally call a remote webservice, but this is for the purpose of this question
List<Person> results = new ArrayList<Person>();
results.add(new Person("John"));
return results;
}
}
And here are my tests
AbstractTest.java
public abstract class AbstractTest {
private InitialContext context;
#BeforeClass(alwaysRun = true)
public void setUp() throws Exception {
System.setProperty("java.naming.factory.initial", "org.apache.openejb.client.LocalInitialContextFactory");
Properties properties = new Properties();
properties.load(getClass().getResourceAsStream("/unittest-jndi.properties"));
context = new InitialContext(properties);
context.bind("inject", this);
}
#AfterClass(alwaysRun = true)
public void tearDown() throws Exception {
if (context != null) {
context.close();
}
}
}
PersonServiceTest.java
#LocalClient
public class PersonServiceTest extends AbstractTest {
#EJB
private PersonService personService;
#Test
public void testPersonService() {
long count = personService.countPersons();
Assert.assertEquals(count, 1l);
}
}
Now, want I want to do is replace the RemotePersonService implementation in PersonServiceImpl.java by a mock using Mockito, and still have the same call in my testPersonService method.
I tried that:
PersonServiceTest.java
#LocalClient
public class PersonServiceTest extends AbstractTest {
#Mock
private RemotePersonService remotePersonService;
#EJB
#InjectMocks
private PersonService personService;
#BeforeMethod(alwaysRun = true)
public void setUpMocks() {
MockitoAnnotations.initMocks(this);
List<Person> customResults = new ArrayList<Person>();
customResults.add(new Person("Alice"));
customResults.add(new Person("Bob"));
Mockito.when(remotePersonService.getAllPersons()).thenReturn(customResults);
}
#Test
public void testPersonService() {
long count = personService.countPersons();
Assert.assertEquals(count, 2l);
}
}
But this doesn't work. The #Mock RemotePersonService is not injected in the PersonService, and the true EJB is still used.
How can I make this work ?
Don't use annotations for your tests. Have a constructor that will wire in all your dependencies.
#Stateless
public class PersonServiceImpl implements PersonService {
#EJB
private RemotePersonService remotePersonService;
// Let your test instantiate a mock service and wire it into your test instance using this constructor.
public PersonServiceImpl(RemotePersonService rps) {
this.remotePersonService = rps;
}
#Override
public long countPersons() {
return remotePersonService.getAllPersons().size();
}
}
Create mocks and pass them to it. Your test might look like this:
#LocalClient
public class PersonServiceTest extends AbstractTest {
#Test
public void testPersonService() {
RemotePersonService mockRemotePersonService = Mockito.mock(RemotePersonService.class);
List<Person> customResults = new ArrayList<Person>();
customResults.add(new Person("Alice"));
customResults.add(new Person("Bob"));
Mockito.when(mockRemotePersonService.getAllPersons()).thenReturn(customResults);
PersonService personService = new PersonServiceImpl(mockRemotePersonService);
long count = personService.countPersons();
Assert.assertEquals(count, 2l);
}
}
I use setters on the class, and Lookup for the ejb
private ServicioAsyncMessaging servicioNotificaciones;
I delete the #EJB --> and on the getter
public ServicioAsyncMessaging getServicioNotificaciones() {
if(servicioNotificaciones == null){
servicioNotificaciones = (ServicioAsyncMessaging)Lookup.getEjb(EjbJndiConstantes.EJB_SERVICIO_ASYNC_MSG);
}
return servicioNotificaciones;
}
public void setServicioNotificaciones(ServicioAsyncMessaging servicioNotificaciones) {
this.servicioNotificaciones = servicioNotificaciones;
}
The lookup es:
public static Object getEjb(String lookupName){
Object t = null;
try {
Context ctx = new InitialContext();
t= ctx.lookup(lookupName);
} catch (NamingException e) {
log.error("getEjb | Error {}",e.getMessage(),e);
}
return t;
}
With those changes the mockito --> inject the mocks on the setter.