Mockito mock java function with inner method - java

I have a class like so:
#Component
public class AddressConverter {
public Function<Address, AddressDTO> convertToDTO = new Function<Address, AddressDTO>() {
public AddressDTO apply(Address address) {
AddressDTO dto = new AddressDTO();
dto.setAddress1(address.getAddress1());
dto.setAddress2(address.getAddress2());
dto.setCity(address.getCity());
dto.setState(address.getState());
dto.setZip(address.getZip());
dto.setZip4(address.getZip4());
return dto;
}
};
}
I have another class that uses this like so:
#Component
public class ProfileConverter {
#Autowired
private AddressConverter addressConverter;
public Function<Profile, ProfileDTO> convertToDTO = new Function<Profile, ProfileDTO>() {
public ProfileDTO apply(Profile profile) {
ProfileDTO dto = new ProfileDTO();
dto.setEmployeeAddress(addressConverter.convertToDTO.apply(profile.getEmployeeAddress()));
return dto;
}
};
}
I am trying to mock the addressConverter class like:
EDIT: HERE IS THE TEST CLASS
public class ProfileConverterTest {
ProfileConverter converter;
AddressConverter addressConverter;
Profile profile;
ProfileDTO dto;
Address address;
AddressDTO addressDTO;
#Before
public void setUp() {
converter = new ProfileConverter();
addressConverter = Mockito.mock(AddressConverter.class);
profile = new Profile();
profile.setProfileId(123L);
dto = new ProfileDTO();
Mockito.when(addressConverter.convertFromDTO.apply(addressDTO)).thenReturn(address);
Mockito.when(addressConverter.convertToDTO.apply(address)).thenReturn(addressDTO);
ReflectionTestUtils.setField(converter, "addressConverter", addressConverter);
address = new Address("1","2","3","4","5","6");
address.setAddressId(123L);
addressDTO = new AddressDTO("hash","1","2","3","4","5","6");
}
#Test
public void applyReturnsProfileDTO() throws Exception {
ProfileDTO result = converter.convertToDTO.apply(profile);
assertEquals(result.getEmployeeAddress().getAddress1(), profile.getEmployeeAddress().getAddress1());
}
}
I keep getting a NullPointerException in my test on the first Mockito.when line. I am thinking it is caused by the mock addressConverter class calling a function calling an inner method. The function might be null?

You are expecting Mockito to call your class constructor which will initialize the field convertToDTO: this is not the case, and the simple test here demonstrate it:
#Test
public void test_that_yeepee_works() {
final Yeepee y = Mockito.mock(Yeepee.class);
Assertions.assertNotNull(y.myObject); // fails.
}
public static class Yeepee {
public Object myObject = new Object();
}
You might try Mockito.spy instead.
Or you need to explicitly do it:
converter = new ProfileConverter();
addressConverter = Mockito.mock(AddressConverter.class);
addressConverter.convertToDTO = (Function<Address, AddressDTO>) Mockito.mock(Function.class);
If you were using getters, Mockito might have done it for you using smart mocks.

I think, NPE is because you have not created a mock for AddressConverter class. You should write something like below:
AddressConverter addressConverter = Mockito.mock(AddressConverter.class);
Mockito.when(addressConverter.apply(any(Address.class))).thenReturn(addressDTO);
Note: any (Address.class) will match any object of Address class. If you want to test weather your address object is being used while calling (mocking) apply method, go ahead and add hashcode() and equals() implementation in your Address class.

Related

isEmpty() on an ArrayList results in false although its size is 0

In a test I inject a mock to another class which seems to work properly. However, when I check the ArrayList if it is empty the result is false although its length/size is 0. How can this happen and how can I solve this problem?
#Slf4j
#Configuration
#RequiredArgsConstructor
#Setter(onMethod_ = #SuppressFBWarnings({"EI_EXPOSE_REP2", "EI_EXPOSE_REP"}))
#Getter(onMethod_ = #SuppressFBWarnings({"EI_EXPOSE_REP2", "EI_EXPOSE_REP"}))
#EnableConfigurationProperties(MyProperties.class)
public class MyConfig {
private final MyProperties myProperties;
private final GenericApplicationContext applicationContext;
#PostConstruct
void init() {
Objects.requireNonNull(myProperties, "myProperties needs not to be null.");
if (/*myProperties.getApps().size() == 0 || */myProperties.getApps().isEmpty()) {
log.info("bla bla bla");
} else {
...
}
}
}
Here's my test class:
#ExtendWith(MockitoExtension.class)
class MyConfigTest {
#Mock
MyProperties myPropertiesMock;
#InjectMocks
MyConfig myConfig;
ApplicationContextRunner contextRunner;
#Test
void should_check_for_empty_apps() {
contextRunner = new ApplicationContextRunner()
.withPropertyValues("foobar.apps[0].name=", "foobar.apps[0].baseUrl=", "foobar.apps[0].basePath=")
;
List apps = Mockito.mock(ArrayList.class);
when(myPropertiesMock.getApps()).thenReturn(apps);
myConfig.init();
contextRunner.run(context -> {
assertThat(apps.size()).isEqualTo(0);
});
}
}
The properties class:
#Slf4j
#Validated
#Data
#Setter(onMethod_ = #SuppressFBWarnings({"EI_EXPOSE_REP2", "EI_EXPOSE_REP"}))
#Getter(onMethod_ = #SuppressFBWarnings({"EI_EXPOSE_REP2", "EI_EXPOSE_REP"}))
#ConfigurationProperties(prefix = MyProperties.CONFIG_PREFIX)
public class MyProperties implements LoggableProperties {
public static final String CONFIG_PREFIX = "foobar";
#Valid
#NestedConfigurationProperty
private List<MyEndpoint> apps = new ArrayList<>();
#Data
public static class MyEndpoint {
// #NotNull
// #NotEmpty
private String baseUrl = "";
private String basePath = "";
// #NotNull
// #NotEmpty
private String name = "";
}
}
List apps = Mockito.mock(ArrayList.class);
When you mock a class, all of its method bodies are completely discarded. Methods with a non-void return type return the default value for that type. For size() that's 0 (default for int), but for isEmpty() that's false (default for boolean).
You can use spy instead of mock to get the actual implementation for methods you don't mock. That's also where the difference between when(x.method()).thenReturn(y) and doReturn(y).when(x).method() differ. The former actually calls the method but discards its result in favour of the mocked return value. The latter doesn't call the method at all (but isn't type safe).
Is there a reason you're mocking the array list? I don't see you using the array list as a mock at all.
‘app’ is a mock. You have to mock any method that you use, otherwise it retrieve type’s default value.

Why Mockito is calling real method?

I have a class Service that calls a method of singleton class. I would like to mock a saveContract method calls.
public class Service {
public Contract save(Contract contract) {
Contract result;
...
result = ContractDao.getInstance().saveContract(contract);
...
return result;
}
}
I modified Service class like this (added a field and a constructor, for testing purposes only):
public class Service {
private final ContractDao contractDao;
public Service() {
this(ContractDao.getInstance());
}
public Service(final ContractDao contractDao) {
this.contractDao = contractDao;
}
public Contract save(Contract contract) {...}
}
And my test class is:
#ExtendWith(MockitoExtension.class)
class ServiceTest {
#Mock
ContractDAO contractDaoMock;
private Service service;
#BeforeEach
public void setup() {
service = new Service(contractDaoMock);
}
#Test
void saveContractTest() {
Contract changedContract = new Contract(...);
when(contractDaoMock.saveContract(any())).thenReturn(changedContract);
Contract givenContract = new Contract(...);
Contract actualContract = service.save(givenContract);
//Assertions
...
}
}
Add mockito-inline dependency and use the MockedStatic to mock the getInstance() method.
Your code should look like that:
#Test
void saveContractTest() {
Contract changedContract = new Contract(...);
try (MockedStatic<ContractDAO> mockedContractDAO = mockStatic(ContractDAO.class) {
mockedContractDAO.when(ContractDAO::getInstance).thenReturn(contractDaoMock);
when(contractDaoMock.saveContract(any())).thenReturn(changedContract);
Contract givenContract = new Contract(...);
Contract actualContract = service.save(givenContract);
//Assertions
...
}
}
Check the docs here to know a bit more about mocking static methods: https://javadoc.io/static/org.mockito/mockito-core/3.9.0/org/mockito/Mockito.html#static_mocks
In Service.save() I have not replaced the line
result = ContractDao.getInstance().saveContract(contract);
with line
result = contractDao.saveContract(contract);
So, we need to use a field instance which we mocked and not the singleton.getInstance().

How to instantiate constructor with dynamic value and Autowire it?

I have instantiated a parametrized constructor here called request operation with dynamic values. how to #Autowire this to Requestclass? subsequently, in Request class, I have created a new RatingResponse how to #Autowire this as well?
class Initializer
public class Intializer
{
NewClass newclass = new NewClass();
String testName = Number + "_" + "Test"; -->getting the String number dynamically
Test test = new Test(testName); -> this is a different class
Operation operation = new RequestOperation(test, newclass ,
sxxx, yyy, zzz); - argumented constructor
opertaion.perform();
}
RequestClass
public class RequestOperation implements Operation {
// the constructor
public RequestOperation(Test test, Sheet reportSheet, XElement element, TestDataManager testDataManager, Report report)
{
this.test = test;
this.newclass = newclass ;
this.sxxx= sxxx;
this.yyy= yyy;
this.zzz= zzz;
}
#Override
public boolean perform(String CompanyName, String Province) {
Response response = new RatingResponse(this.test, this.reportSheet,
callService(this.buildRequest(CompanyName, Province)), this, this.report);-> create a new paramterizedconstructor
}
private String buildRequest(String CompanyName, String Province) {
return pm.getAppProperties().getProperty(constructedValue); }
}
**Response class **
public class RatingResponse implements Response {
public RatingResponse(Test test, Sheet reportSheet, Object obj, RequestOperation requestOperation, Report report) {
this.test = test;
if (obj instanceof Document) {
this.document = (Document) obj;
}
this.operation = requestOperation;
this.reportSheet = reportSheet;
this.report = report;
}
** interface **
#Component
public interface Operation {
public boolean perform(String Name, String Province);
}
#Component
public interface Response {
void construct();
}
In spring boot, you can autowire only types marked with #Bean or classes marked with #Component or its derivitives like #Service, #Controller
The speciality of these annotations is that only a single instance of the class is kept in memory.
So if your requirement needs you to create new classes for each set of new dynamic values, then autowiring them is not the right way to go.
However if you have limited number of possible dynamic values that your class can have, you can create beans for each of them like this
#Configuration
class MyBeans{
#Bean
public RatingResponse ratingResponse(){
Response response = new RatingResponse(this.test, this.reportSheet,
callService(this.buildRequest(CompanyName, Province)), this, this.report);
return response
}
}
Then in the class you need to use it, you can do
#Autowired
RatingResponse ratingResponse

How to mock array of class using Mockito

I want to mock Order array class Order[].class. below mockMapper reads Order[].class and need to return Order[].class.
Service class
public class OrdersConnectorImpl {
public Order getOrderById(String Id, OrderType orderType) throws Exception {
Response response = null;
response = orderServiceTarget.queryParam("ID", Id).queryParam(ORDER_TYPE, orderType).request().accept(MediaType.APPLICATION_JSON)
.get();
final StatusType responseStatus = response.getStatusInfo();
final String serverResponseStr = response.readEntity(String.class);
if (responseStatus.equals(Response.Status.OK)) {
objectMapper = getObjectMapper(); // we have a private method in this class
Order[] orders = objectMapper.readValue(serverResponseStr, Order[].class);
if(orders.length>0) {
return orders[0];
}
}
}
}
Test class
public class OrdersConnectorImplTest {
private ObjectMapper mockMapper;
private class MockOrdersConnectorImpl extends OrdersConnectorImpl {
#Override
protected ObjectMapper getObjectMapper() {
return mockMapper;
}
}
}
#Test
public void test_getRenewalOrderForContract() throws Exception {
Response mockResponse = mock(javax.ws.rs.core.Response.class);
Order mockOrder = mock(Order.class);
when(mockResponse.getStatusInfo()).thenReturn(Status.OK);
when(mockResponse.readEntity(String.class)).thenReturn("{}");
when(mockBuilder.get()).thenReturn(mockResponse);
when(mockMapper.readValue("{}", Order[].class)).thenReturn(mockOrder); // this is the problem line
orderConnector.getOrderById("id", OrderType.NEW);
}
}
Please correct me here how to return expected.
You have autowired mockMapper which means, the actual object of ObjectMapper will be injected.
And in the when part, you setting up the behavior of mockMapper, which shouldn't be the case.
Edit 1
In your case, there is no need for mocking the Order class, you have to return the array Order which you can create in the tests.
For your information, with Junit there is no way, you can mock the object which is been created inside the method.

org.mockito.exceptions.misusing.MissingMethodInvocationException

I am getting following exceptions when I run Junit test.
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
you stub either of: final/private/equals()/hashCode() methods. Those methods cannot be stubbed/verified.
inside when() you don't call method on mock but on some other object.
the parent of the mocked class is not public. It is a limitation of the mock engine.
Following is my code and the exception was thrown at the second when statement. I don't think that my test code didn't violate what the exception claims. I spent for a while, but couldn't figure out. Could someone help? What I need to test is getPermProducts method. In the getPermProducts method, I want to ignore isTempProduct method. So, when p1 came, I want it returns false, and when p2 came, I want it returns true etc..
#Named(ProductManager.NAME)
public class ProductManager {
#Resource(name = ProductService.NAME)
private ProductService productService;
public List<Product> getPermProducts(Set<Product> products) {
Iterator<Product> it = products.iterator();
List<Product> cProducts = new ArrayList<Product>();
Product p;
while (it.hasNext()) {
p = it.next();
if (!isTempProduct(p)) {
cProducts.add(p);
}
}
return cProducts;
}
public Boolean isTempProduct(Product product) {
if (product instanceof PermProduct) {
return false;
}
Set<ProductItems> pItems = product.getProductItems();
if (pItems.isEmpty()) {
return false;
}
Iterator<ProductItem> itr = pItems.iterator();
while (itr.hasNext()) {
if (itr.next() instanceof TempItem) {
return true;
}
}
return false;
}
public Product getProduct(Integer productId) {
Product p = productService.getProduct(productId);
return p;
}
}
#RunWith(MockitoJUnitRunner.class)
public class ProductManagerTest {
#InjectMocks
private ProductManager mockProductManager;
#Mock
private ProductService mockProductService;//not being used here
private static final Integer PRODUCT_ID_1 = 1;
private static final Integer PRODUCT_ID_2 = 2;
#Test
public void getProduct(){
Product p1 = mock(PermProduct.class);
p1.setProductId(PRODUCT_ID_1);
when(mockProductManager.getProductId()).thenReturn(PRODUCT_ID_1);
when(mockProductManager.isTempProduct(p1)).thenReturn(false);
Product p2 = mock(TempProduct.class);
p2.setProductId(PRODUCT_ID_2);
when(mockProductManager.isTempProduct(p2)).thenReturn(true);
List<Product> products = Mock(List.class);
products.add(p1);
products.add(p2);
Iterator<Product> pIterator = mock(Iterator.class);
when(prodcuts.iterator()).thenReturn(pIterator);
when(pIterator.hasNext()).thenReturn(true, true, false);
when(pIterator.next()).thenReturn(p1, p2);
asserEquals(1, mockProductManager.getPermProducts(products).size());
}
}
SOLUTION: I updated my test based on enterbios's answer. I used partial mocking, but as enterbios suggested, we should avoid it, but sometimes we need it. I found that we can have both non-mocked and partial mocked class same time.
#RunWith(MockitoJUnitRunner.class)
public class ProductManagerTest {
#InjectMocks
private ProductManager productManager;//not being used here
#Mock
private ProductService mockProductService;//not being used here
#Spy
private OtherService other = new OtherService();//not being used here
#InjectMocks
final ProductManager partiallyMockedProductManager = spy(new ProductManager());
private static final Integer PRODUCT_ID_1 = 1;
private static final Integer PRODUCT_ID_2 = 2;
#Test
public void getProduct() {
Product p1 = new PermProduct();
p1.setProductId(PRODUCT_ID_1);
Product p2 = new Product();
p2.setProductId(PRODUCT_ID_2);
List<Product> products = new ArrayList<Product>();
products.add(p1);
products.add(p2);
doReturn(false).when(partiallyMockedProductManager).isTempProduct(p1);
doReturn(true).when(partiallyMockedProductManager).isTempProduct(p2);
assertEquals(1, partiallyMockedProductManager.getPermProducts(products).size());
verify(partiallyMockedProductManager).isTempProduct(p1);
verify(partiallyMockedProductManager).isTempProduct(p2);
}
}
Your mockProductManager is actually not a mock but an instance of ProductManager class. You shouldn't mock a tested object. The way to mock some methods from tested object is using a spy but I recommend you to not use them, or even to not think about them unless you're fighting with some ugly legacy code.
I think your second 'when' should be replaced with assertion, like:
assertFalse(mockProductManager.isTempProduct(p1));
because what you really want to check in this test is if productManager.isTempProduct(p1) returns false for all instances of PermProduct. To verify results of some method calls/objects states you should use assertions. To make your life with assertions easier you can take a look on some helpful libraries like Hamcrest or FEST (http://docs.codehaus.org/display/FEST/Fluent+Assertions+Module). FEST is simpler for beginners I think.

Categories