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))
Related
I am currently working on a project where I have created the following custom Repository:
public interface ServiceRepository<T extends ServiceEntity> extends JpaRepository<T, UUID>, ServiceRepositoryCustom {
}
public interface ServiceRepositoryCustom {
List<ServiceEntity> findAllContainingName(String query);
}
#Repository("Repo")
public class ServiceRepositoryCustomImpl implements ServiceRepositoryCustom {
private final EntityManager em;
public ServiceRepositoryCustomImpl(EntityManager em) {
System.out.println("I got constructed");
this.em = em;
}
#Override
public List<ServiceEntity> findAllContainingName(String name) {
System.out.println("I got called with: " + name);
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<ServiceEntity> cq = cb.createQuery(ServiceEntity.class);
Root<ServiceEntity> serviceEntity = cq.from(ServiceEntity.class);
List<Predicate> predicates = new ArrayList<>();
if(name != null) {
// predicates.add(cb.equal(serviceEntity.get("name"), name));
predicates.add(cb.like(serviceEntity.get("name"), name + "%"));
}
cq.where(predicates.toArray(predicates.toArray(new Predicate[0])));
return em.createQuery(cq).getResultList();
}
}
The print statement "I got called with: " never gets called. So for whatever reason Spring Boot is not running the method through my custom implementation.
Any suggestions? Any help is much appreciated
Edit:
Here is the code that injects and uses the Repository in question
#Repository
public interface PineappleServiceRepository extends ServiceRepository<PineappleServiceEntity> {
}
#Component("Registry")
#DependsOn({"Context", "Repo"})
public class Registry {
private final List<ServiceRepository<? extends ServiceEntity>> serviceRepositories = new ArrayList<>();
public Registry(PineappleServiceRepository pineappleServiceRepository) {
this.serviceRepositories.add(pineappleServiceRepository);
}
}
Edit 2:
The code prints "I got constructed"
Edit 3:
Class where findAllContainingName is called
#RestController
#RequestMapping("/test")
#DependsOn("Registry")
public class ServiceController {
private final Registry registry;
public ServiceController(#NotNull Registry registry) {
this.registry = registry;
}
#GetMapping("")
List<ServiceEntity> all(#RequestParam("q") String query) {
return getAllServices(query);
}
private #NotNull List<ServiceEntity> getAllServices(String query) {
List<ServiceEntity> response = new ArrayList<>();
for(ServiceRepository<? extends ServiceEntity> repo: this.registry.getServiceRepositories()){
response.addAll(repo.findAllContainingName(query));
}
return response;
}
}
Edit 4:
Here the entities:
#Entity
#Table(name = "services")
public abstract class ServiceEntity {
protected #Id
UUID id = UUID.randomUUID();
protected String name;
// Constructor + Getters and Setters
}
#Entity
public class PineappleServiceEntity extends ServiceEntity {
// Additional Properties, matching Constructors, Getters and Setters
}
So I was able to reproduce your problem and fix it. Issue with your code is that your PineappleServiceRepository is not extending ServiceRepositoryCustom directly. It seems your repository needs to implement it directly if you are accessing custom repository methods from that repository. I got that idea from this post.
So to fix your issue, either remove PineappleServiceRepository(as you don't have any properties in PineappleEntity) and use ServiceRepository to call that custom method or make PineappleServiceRepository extend ServiceRepositoryCustom.
I have pushed changes to GitHub with fix. You can take a look. If you want to keep PineappleServiceRepository and access custom method using this repository, let me know, I can update code.
I want to add two columns and place the result in the third. My table conrains 100+ line.
My model:
My repository:
import java.util.List;
#Repository
public interface OilRepo extends JpaRepository<OilModel,Long> {
}
Controller:
#RestController
#RequestMapping()
public class OilController {
#Autowired
private OilService oilService;
#GetMapping(value = "/all")
public List<OilModel> oilModels() { return oilService.getOilModel();}
#PostMapping(value = "/save")
public List<OilModel> oilModel(#RequestBody List<OilModel> oilModel){
return oilService.saveOil(oilModel); }
}
and Services
import java.util.List;
#Service
public class OilService {
#Autowired
private OilRepo oilRepo;
public List<OilModel> getOilModel() { return oilRepo.findAll(); }
public List<OilModel> saveOil(List<OilModel> oilModels){
oilModels.stream().map(oilModel -> oilModel.average =
oilModel.getO_ai_92()+oilModel.getO_ai_95());
return oilRepo.saveAll(oilModels);
}
}
How can I write the service correctly to make this code work?
You can do it inside getAverage() method as shown below:-
public class OilModel {
#Access(AccessType.PROPERTY)
private double average;
...
...
...
public Double getAverage() {
return get0_ai_92() + get0_ai_95();
}
}
and store the list directly without doing any operations on it.
Note:- make sure to add #Access(AccessType.PROPERTY) on average field to allow jpa access the value from the method, not from the field.
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.
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
I am having two java class as below,
public class Class1{
private Object actionObject;
public Object getActionObject() {
return actionObject;
}
public void setActionObject(Object actionObject) {
this.actionObject = actionObject;
}
}
Second class
public class Class2 {
private Long id;
private int idver;
private int valueDate;
}
There are two statement as below,
Class1 deserializedValue = (Class1) event.getDeserializedValue();
Class2.class.isAssignableFrom(deserializedValue.getActionObject().getClass());
I want to mock the second statement
Class2.class.isAssignableFrom(deserializedValue.getActionObject().getClass());
how can i do this?
For testing purposes you can use a strategy pattern. You just need an interface or an abstract class with two different implementations. One of them is the mock implementation, something like this:
public interface EventStrategy {
// More methods...
boolean isAssignableFrom(final Object object);
}
public class MyEvent implements EventStrategy {
public boolean isAssignableFrom(final Object object) {
return Class2.class.isAssignableFrom(object.getClass());
}
}
public class MockEvent implements EventStrategy {
public boolean isAssignableFrom(final Object object) {
return true;
}
}