UnitTest a SpringBatch FieldSetMapper - java

I got the following custom FieldSetMapper
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;
import de.BasicProperty;
public class PersonItemFieldSetMapper implements FieldSetMapper<PersonItem> {
#Override
public PersonItem mapFieldSet(final FieldSet fieldSet) throws BindException {
PersonItem person = new PersonItem();
person.setLastName(fieldSet.readString(BasicProperty.BASICPROP_LASTNAME));
person.setFirstName(fieldSet.readString(BasicProperty.BASICPROP_FIRSTNAME));
person.setEmployeeType(fieldSet.readString("EmployeeType"));
person.setFormOfAdress(fieldSet.readString(BasicProperty.BASICPROP_FORMOFADDRESS));
person.setEMail(fieldSet.readString(BasicProperty.BASICPROP_EMAIL));
person.setUpn(fieldSet.readString(BasicProperty.BASICPROP_UPN));
person.setWorkforceId(fieldSet.readString(BasicProperty.BASICPROP_WORKFORCE_ID));
person.setInstitute(fieldSet.readString(BasicProperty.BASICPROP_INSTITUTE));
person.setPhoto(fieldSet.readString(BasicProperty.BASICPROP_PHOTO));
return person;
}
}
At the moment i am trying to write a unit-test for this mapper.
First Question: Is this reasonable?
Second Question: How can i achieve this?

Yes you can write Test Cases for mapFieldSet()
You can always write such test cases to make sure your mapping are good!
// Using EasyMock to mock FieldSet
#Test
public void mapFieldSetTest()
{
FieldSet mockFieldSet = EasyMock.createMock(FieldSet.class);
EasyMock.expect(mockFieldSet.readString("LNAME")).andReturn("Doe");
EasyMock.expect(mockFieldSet.readString("FNAME")).andReturn("John");
EasyMock.expect(mockFieldSet.readString("ETYPE")).andReturn("PART-TIME");
EasyMock.expect(mockFieldSet.readString("FADDRESS")).andReturn("191, Santa Clara");
EasyMock.expect(mockFieldSet.readString("EMAIL")).andReturn("john.Doe#fb.com");
EasyMock.expect(mockFieldSet.readString("UPN")).andReturn("1111111111");
EasyMock.expect(mockFieldSet.readString("WFID")).andReturn("22222222");
EasyMock.expect(mockFieldSet.readString("INS")).andReturn("CA University College");
EasyMock.expect(mockFieldSet.readString("PIC")).andReturn("c:\\john_doe.jpg");
EasyMock.replay(mockFieldSet);
// call the method under test
PersonItem actual = fieldSetMapper.mapFieldSet(mockFieldSet);
EasyMock.verify(mockFieldSet);
// assert actual data by getters..
}

Related

Rest Assured & Spring - Value Becomes Null After First Test

I have a strange problem. I've written my API and I just wanted to test it.
I wrote a simple test code by using Restassured:
package com.example.restservicetest;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import java.util.*;
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class RestServiceTestApplicationTests {
#LocalServerPort
private int port;
private Response response;
private List<Object> folderList;
#Test
public void getWholeFolders() {
response = RestAssured.given().port(port).when().get("/api/opening").then().statusCode(200).extract().response();
folderList= response.jsonPath().getList("folders");
}
#Test
public void getRandomFolderNumber() {
Random rand = new Random();
RestAssured.given().port(port).when().get("/api/opening/folder/" + rand.nextInt(folderList.size()-1)).then().statusCode(200);
}
}
When I debug my test, at the end of first getWholeFolders test, I see that folderList is not empty as I expected. My whole folder list is assigning to it.
But when the time is for 2nd test getRandomFolderNumber, I see that folderList becomes null.
Why does it become null?
As Andriy mentiond in comment, JUnit Jupiter will use a default lifecycle mode, it means JUnit creates a new instance of each test class before executing each test method TestInstance.Lifecycle.PER_METHOD.
To change that, you change PER_METHOD --> PER_CLASS (basically means one instance of test class for all test method).
One more subtle thing, you need to set order for test method to make sure getRandomFolderNumber always run after getWholeFolders
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class RestServiceTestApplicationTests {
...
#Test
#Order(1)
public void getWholeFolders() {
...
}
#Test
#Order(2)
public void getRandomFolderNumber() {
...
}
}

Mockito When...Then Return - return ignored?

I'm currently on a course learning Spring-boot and I'm stuck with testing a project - any help is much appreciated as I'm a beginner here.
I have a rest controller test, using Mockito that appears to be ignoring "ThenReturn" when a method is invoked using Mockito.when().
Here is the whole class:
package com.example.demo.controllers;
import com.example.demo.TestUtils;
import com.example.demo.model.persistence.AppUser;
import com.example.demo.model.persistence.repositories.CartRepository;
import com.example.demo.model.persistence.repositories.UserRepository;
import com.example.demo.model.requests.CreateUserRequest;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import java.util.Optional;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class UserControllerTest {
private UserController userController;
private UserRepository userRepository = mock(UserRepository.class);
private CartRepository cartRepository = mock(CartRepository.class);
private BCryptPasswordEncoder bCryptPasswordEncoder = mock(BCryptPasswordEncoder.class);
#Before
public void initTest(){
userController = new UserController();
TestUtils.injectObjects(userController, "userRepository", userRepository);
TestUtils.injectObjects(userController, "cartRepository", cartRepository);
TestUtils.injectObjects(userController, "bCryptPasswordEncoder", bCryptPasswordEncoder);
AppUser appUser = TestUtils.getAppUser();
when(userRepository.findById(0L)).thenReturn(Optional.of(appUser));
when(bCryptPasswordEncoder.encode("testPassword")).thenReturn("hashedPassword");
}
#Test
public void testFindUserById(){
ResponseEntity<AppUser> response = userController.findById(0L);
System.out.println(response);
}
#Test
public void testCreateUser() throws Exception{
CreateUserRequest createUserRequest = new CreateUserRequest();
createUserRequest.setUsername("testUser");
createUserRequest.setPassword("testPassword");
createUserRequest.setConfirmPassword("testPassword");
ResponseEntity<AppUser> response = userController.createUser(createUserRequest);
assertNotNull(response);
assertEquals(200, response.getStatusCodeValue());
AppUser createdUser = response.getBody();
assertNotNull(createdUser);
assertEquals(0, createdUser.getId());
assertEquals("testUser", createdUser.getUsername());
assertEquals("hashedPassword", createdUser.getPassword());
}
}
The test called "testCreateUser" passes without a problem. It's the test called "testFindUserById" that is giving me a problem.
Here is the controller method I'm trying to test (all working fine when tested in Postman):
public ResponseEntity<AppUser> findById(#PathVariable Long id) {
try{
log.info("UserIDSearch = " + id);
System.out.println("UserIDSearch = " + id);
Optional<AppUser> optionalAppUser = userRepository.findById(id);
if(optionalAppUser.isPresent()){
log.info("UserIdFound = " + id);
return ResponseEntity.ok(optionalAppUser.get());
}else{
throw new ApiException(ExceptionTypes.SEARCHUSER, id.toString());
}
}catch(ApiException a){
return ResponseEntity.notFound().build();
}
}
The repository being mocked in the test class is just a straightforward JpaRepository:
public interface UserRepository extends JpaRepository<AppUser, Long> {
Optional<AppUser> findByUsername(String username);
public Optional<AppUser> findById(long id);
}
The output I get from running the testFindUserById() test is the following:
UserIDSearch = 0
<404 NOT_FOUND Not Found,[]>
I guess what I'm trying to achieve here is that the test uses the when().thenReturn() to simulate an OK response from the mocked userRepository, but instead it actually performs the search and returns the "Not found". Can anyone help? Thanks so much!
Seems to be a problem with autoboxing. Change the method public Optional<AppUser> findById(long id); to accept Long instead.
I think #Janar is correct, but I'll explain why.
When you write "when(userRepository.findById(0L)).thenReturn(Optional.of(appUser))", what Mockito does is set start monitoring calls to the indicated method (findById) and comparing the argument to "0L", which is a Java long int, which is not an object.
The actual method takes a java.lang.Long, which is an object. The two are not equal.
You can fix it by changing the findById method, as #Janar suggests, but that is not what I would do. I assume that the production code is using a java.lang.Long for a practical reason. Instead, I would change the test to:
when(userRepository.findById(Long.valueOf(0L))).thenReturn(Optional.of(appUser));
My case was not the same of your findById but I hope it helps.
Summary:
mockito is sensible with the passed arguments and it works better with simple or primitive data types
On my case, this sentence was ignored:
doReturn(result).when(scriptExecutor).
runScript(connection, new StringReader("selec * from dual;"));
After some hours of attempts, I change the definition of runScript to receive a simple string instead StringReader.
From this:
public ArrayList runScript(Connection conn, StringReader reader)
To this:
public ArrayList runScript(Connection conn, String query)
Then the mocked sentence was picked and everything works as expected:
doReturn(result).when(scriptExecutor).
runScript(connection, "selec * from dual;");
Basically if I use a StringReader, didn,t work. But with a simple String, it works!!

Issue with stubbing/mocking the method with makes a DB call

I am having issue with Mocking a JDBC call using the MockitoJUnitRunner.
Somehow Mockito is not mocking the actual call even though I have below subbing line into the test class.
when(readOnlyJdbcTemplate.query(anyString(), any(Object[].class), any(int[].class), any(FeatureCollectionResponseExtractor.class))).thenReturn(actual);
Very similar mocking is working in another class for very similar type of method. The only difference between them is my other class does have 3 parameters instead of 4 parameters. Below is the code which is actually mocking successfully for different class.
when(readOnlyJdbcTemplate.query(anyString(), any(Object[].class), any(FeaturesResultExtractor.class))).thenReturn(actual);
Below is my actual code.
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.inject.Inject;
import javax.inject.Named;
import java.net.HttpURLConnection;
import java.sql.Types;
import static com.accounts.features.utils.Constants.INTERNAL_SERVER_ERROR;
#Profile
#Log
#Named("featureLibraryDao")
public class FeatureLibraryDaoImpl implements FeatureLibraryDao {
private static final Logger LOGGER = LogManager.getLogger(FeatureLibraryDaoImpl.class);
#Value("${feature.library.function.sql.query}")
private String sqlSelectQuery;
#Inject
#Named("readOnlyJdbcTemplate")
private JdbcTemplate readOnlyJdbcTemplate;
#Override
public FeatureCollectionDTO getFeaturesData(FeatureRequest request) {
try {
int[] argTypes = new int[] { Types.BIGINT, Types.VARCHAR, Types.SMALLINT};
return readOnlyJdbcTemplate.query(sqlSelectQuery, new Object[] {
Long.parseLong(request.getAccountId()), request.getRequestedFeatures(), request.getApplicationSuffix()
}, argTypes,
new FeatureCollectionResponseExtractor(request));
} catch (CustomException cbe) {
throw cbe;
} catch (Exception ex) {
LOGGER.error("getFeaturesData method failed with error message:{}", ex.getMessage(), ex);
CustomErrorCode error = new CustomErrorCode(INTERNAL_SERVER_ERROR);
error.setDeveloperText(ex.getMessage());
throw new CustomSystemException(error, HttpURLConnection.HTTP_INTERNAL_ERROR);
}
}
}
and below is my test class.
#RunWith(MockitoJUnitRunner.class)
public class FeatureLibraryDaoImplTest {
#InjectMocks
private FeatureLibraryDaoImpl dao;
#Mock
private JdbcTemplate readOnlyJdbcTemplate;
private List<String> features = Arrays.asList("excl_clsd_ind_only", "excl_chrgoff_ind_only", "excl_dsput_ind_only");
#Test
public void getFeaturesDataWhenSuccess() {
//given
FeatureRequest request = getFeatureRequest();
FeatureCollectionDTO actual = new FeatureCollectionDTO(features);
when(readOnlyJdbcTemplate.query(anyString(), any(Object[].class), any(int[].class), any(FeatureCollectionResponseExtractor.class))).thenReturn(actual);
//when
FeatureCollectionDTO dto = dao.getFeaturesData(request);
//then
assertThat(dto, notNullValue());
}
}
Any suggestion about what is wrong here? Is there any issue with any(int[].class) ?
I do see you are not passing the sql query sqlSelectQuery value during the test case, But during mock you specified anyString() so it must be some value but not null. Since you are using spring project, you can use ReflectionTestUtils to set the field value for object
#Before
public void setUp() {
ReflectionTestUtils.setField(dao, "sqlSelectQuery", "query");
}
Hey Guys thanks much for all your suggestions. So I found that Test code is perfectly fine. Some how #Value tag wasn't injecting the actual value the sqlSelectQuery in the main code file.
#Value("${feature.library.function.sql.query}") private String sqlSelectQuery;
Instead of that I changed code to private String sqlSelectQuery = "${feature.library.function.sql.query}" and all test cases are passing.
Somehow sqlSelectQuery was't getting the value and hence Mockito wasn't mocking the actual method call. I am yet reviewing why #value is not working as it should be.

Powermock/EasyMock: Set expectation on final method that would throw exception

How do I set an expectation on a final method if I can't safely invoke that method at all? PowerMock is supposed to ensure the invocation is mocked, but I can't even get to that stage:
WithFinal.java:
public class WithFinal {
public final void finalMethod() {
throw new RuntimeException();
}
}
CallsFinal.java:
public class CallsFinal {
private WithFinal withFinal;
public CallsFinal(WithFinal withFinal) {
this.withFinal = withFinal;
}
public void callFinal() {
withFinal.finalMethod();
}
}
PowerMockTest.java:
import org.easymock.EasyMock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.core.classloader.annotations.PrepareForTest;
import static org.powermock.api.easymock.PowerMock.*;
#RunWith(PowerMockRunner.class)
#PrepareForTest(CallsFinal.class)
public class PowerMockTest {
#Test public void testFinal() {
WithFinal mock = createMock(WithFinal.class);
CallsFinal callsFinal = new CallsFinal(mock);
mock.finalMethod();
EasyMock.expectLastCall().atLeastOnce();
replay(mock);
callsFinal.callFinal();
verify(mock);
}
}
I get a RuntimeException on the very first call to mock.finalMethod(), which makes sense, but I thought the whole point of PowerMock was to make this possible?
There was a simple mistake in the test class: instead of #PrepareForTest(CallsFinal.class), it should have been #PrepareForTest(WithFinal.class).
PowerMock only requires that the calling class be prepared for test when mocking a system class from the JRE; otherwise, it's the class to be mocked itself that needs to get prepared.
Finally, I will mention there is another mocking library that can be used here, which I happen to develop: JMockit. With it, the test can be written as:
import org.junit.*;
import mockit.*;
public class JMockitTest {
#Tested CallsFinal callsFinal;
#Injectable WithFinal mock;
#Test public void testFinal() {
new Expectations() {{ mock.finalMethod(); }};
callsFinal.callFinal();
}
}
Using PowerMock, you can mock skip a internal method call instead of direct method call.
For example you want to test callFinal method of CallsFinal class which internally calling finalMethod of WithFinal class. So in this case if you don't want to instantiate WithFinal class then you need to mock WithFinal object to skip internal call for finalMethod.

mockito better expected exception test using spy

How can I make the 3rd test to check for the existence of cause1 in the message of the exception? I also listed in the first two tests that have drawbacks. First is not checking for the message second needs a lot of boilerplate code.
public class CheckExceptionsWithMockitoTest {
#Test(expected = RuntimeException.class)
public void testExpectedException1() {
A a = new A();
a.doSomethingThatThrows();
}
#Test
public void testExpectedException2() {
A a = new A();
try {
a.doSomethingThatThrows();
fail("no exception thrown");
} catch (RuntimeException e) {
assertThat(e.getMessage(), org.hamcrest.Matchers.containsString("cause1"));
}
}
#Test
public void testExpectedException3() {
A a = new A();
A spyA = org.mockito.Mockito.spy(a);
// valid but doesnt work
// doThrow(new IllegalArgumentException()).when(spyA).doSomethingThatThrows();
// invalid but in the spirit of what i want
//chekThrow(RuntimeException.class,containsString("cause1")).when(spyA).doSomethingThatThrows();
}
}
I couldn't find in Mockito something that works but there is something that looks like could be possible (at the level of syntax) and capabilities.
Using catchexception I created the test like this
import static com.googlecode.catchexception.CatchException.*;
import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.junit.*;
public class CheckExceptionsWithMockitoTest{
//...
#Test
public void testExpectedException3() {
A a = new A();
verifyException(a,IllegalArgumentException.class)
.doSomethingThatThrows();
//if more details to be analized are needed
assertThat(
(IllegalStateException) caughtException(),
allOf(
is(IllegalStateException.class),
hasMessageThat(
containsString("is not allowed to add counterparties")),
hasNoCause()));
//more asserts could come
assertNotNull(a);
}
}
Use catch-exception library, or I guess that the solution you are looking for is your second implementation.
#expected doesn't provide any way to assert on the thrown exception except for its class, so you can't avoit try/catching (not that much boiler plate code !)
Mockito doesn't provide something likes a verifyThrows method.
So you can trade try/catching for an additional library : using catch-exception, you'll be able to catch exception in a single line and have it ready for further assertion(s).
Sample source code
A a = new A();
when(a).doSomethingThatThrows();
then(caughtException())
.isInstanceOf(IllegalStateException.class)
.hasMessageContaining("is not allowed to add counterparties")
.hasNoCause();
Dependencies
'com.googlecode.catch-exception:catch-exception:1.2.0'
If A is your system under test, it doesn't make any sense to mock it, and it rarely makes sense to spy on it. Your implementation in testExpectedException2 is the right one; the boilerplate code is necessary because without a try block Java will not let any code run after the method is intercepted (as I described in this previous SO answer).
Though Mockito won't be any help, JUnit will. The #Test(expected=foo) parameter actually has a more-flexible alternative, the built-in ExpectedException JUnit rule:
public class CheckExceptionsWithMockitoTest {
#Rule public ExpectedException thrown = ExpectedException.none();
#Test
public void testExpectedException1() {
A a = new A();
thrown.expect(RuntimeException.class);
thrown.expectMessage(containsString("cause1"));
a.doSomethingThatThrows();
}
}
Mockito would come in handy in a separate test checking whether your method wraps an arbitrary exception while preserving its message, which would look roughly like this:
#Test
public void doSomethingShouldWrapExceptionWithPassedMessage() {
Dependency dependency = Mockito.mock(Dependency.class);
when(dependency.call()).thenThrow(new IllegalArgumentException("quux"));
A a = new A(dependency);
thrown.expect(RuntimeException.class);
thrown.expectMessage(containsString("quux"));
a.doSomethingThatThrows();
}
Be careful to avoid the temptation to make this a common pattern in your tests. If you are catching an exception thrown from your system under test, you're effectively ceding control back to the SUT's consumer. There should be little left to test in the method afterwards, except the properties of the exception and MAYBE the state of your system, both of which should be rare enough that try/catch boilerplate is forgivable.
If you have the opportunity to use scala, scalaTest's fun suite has concise way of testing exceptions using intercept (http://www.scalatest.org/getting_started_with_fun_suite).
It's as simple as
test(a list get method catches exceptions){
intercept[IndexOutBoundsException]{
spyListObject.get(-1)
}
}
You could potentially write your tests to your java project in scala if you are looking for easy to write / clear test. But this may present other challenges.
Updated answer for 06/19/2015 (if you're using java 8)
Using assertj-core-3.0.0 + Java 8 Lambdas
#Test
public void shouldThrowIllegalArgumentExceptionWhenPassingBadArg() {
assertThatThrownBy(() -> myService.sumTingWong("badArg"))
.isInstanceOf(IllegalArgumentException.class);
}
Reference: http://blog.codeleak.pl/2015/04/junit-testing-exceptions-with-java-8.html
Using catchexception I created the test like this
import static com.googlecode.catchexception.CatchException.*;
import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.junit.*;
public class CheckExceptionsWithMockitoTest{
//...
#Test
public void testExpectedException3() {
A a = new A();
verifyException(a,IllegalArgumentException.class)
.doSomethingThatThrows();
//if more details to be analized are needed
assertThat(
(IllegalStateException) caughtException(),
allOf(
is(IllegalStateException.class),
hasMessageThat(
containsString("is not allowed to add counterparties")),
hasNoCause()));
//more asserts could come
assertNotNull(a);
}
}
If you have a look in Mockito.class on spy method it creates mock with spiedInstance:
public static <T> T spy(T object) {
return MOCKITO_CORE.mock((Class<T>) object.getClass(), withSettings()
.spiedInstance(object)
.defaultAnswer(CALLS_REAL_METHODS));
}
In MockSettings it is possible to register Invocation listeners: https://static.javadoc.io/org.mockito/mockito-core/3.0.0/org/mockito/listeners/InvocationListener.html
I created simple listener which stores all reported invocations:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.mockito.listeners.InvocationListener;
import org.mockito.listeners.MethodInvocationReport;
public class StoringMethodInvocationListener implements InvocationListener {
private List<MethodInvocationReport> methodInvocationReports = new ArrayList<>();
#Override
public void reportInvocation(MethodInvocationReport methodInvocationReport) {
this.methodInvocationReports.add(methodInvocationReport);
}
public List<MethodInvocationReport> getMethodInvocationReports() {
return Collections.unmodifiableList(methodInvocationReports);
}
}
After the invocation you can go through reports and find the one needed and verify that stored throwable is the one expected.
Example:
StoringMethodInvocationListener listener = new StoringMethodInvocationListener();
Consumer mock2 = mock(Consumer.class, withSettings()
.spiedInstance(consumerInstance)
.defaultAnswer(CALLS_REAL_METHODS)
.invocationListeners(listener));
try {
mock2.listen(new ConsumerRecord<String, String>(RECEIVER_TOPIC, 0, 0, null, "{}"));
} catch (Exception e){
//nothing
}
Assert.notEmpty(listener.getMethodInvocationReports(), "MethodInvocationReports list must not be empty");
Assert.isInstanceOf(BindException.class, listener.getMethodInvocationReports().get(1).getThrowable());

Categories

Resources