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.
Related
I am trying to setup Junit, but just can't seem to, primarily because my use case is not basic (tho my skill level is).
I was given a jar as part of an assignment, and I can run the program without issue. However, I am unable to set it up properly in eclipse, such that it runs. The main method is in the jar package, so I cannot see it to give more information about it.
Here is my derived class that I would like to test.
package jimmy.kilmer.com;
import java.awt.Color;
import jarPackageImports.AI;
import jarPackageImports.MovementAction;
import jarPackageImports.GameInfo;
import jarPackageImports.PlayerAction;
public class GameAI extends AI {
public gameAI(Info info) {
super(info);
}
public Color getColor() {
return Color.MAGENTA;
}
public String getName() {
return "Usain Bolt";
}
public PlayerAction update() {
// TODO game movement actions
// all available methods not listed here...
info.getVelocity();
info.getX();
info.getY();
MovementAction steeringBehavior = null;
return steeringBehavior;
}
public int[][] populateAllPossibleNodes() {
int[][] allPossibleNodes = new int[screenWidth/20][screenHeight/20];
return allPossibleNodes;
}
}
I have tried various different ways to instantiate an object in junit for it to run, but I simply cannot, and thus I can only test static method -- which isn't so useful.
This is what the template looks like.
package jimmy.kilmer.com;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class GameKITest {
private Info info;
private GameAI gameAiInstance = new GameAI((jarPackageImports.Info) Info info);
#BeforeAll
static void setUpBeforeClass() throws Exception {
}
#AfterAll
static void tearDownAfterClass() throws Exception {
}
#BeforeEach
void setUp() throws Exception {
}
#AfterEach
void tearDown() throws Exception {
}
#Test
void testPopulateAllPossibleNodes() {
// 1. given/arrange
int[][] array1 = new int[80][65];
// 2. when/act
int[][] array2 = GameAiInstance.populateAllPossibleNodes();
// 3. then/assert
assertArrayEquals(array1, array2);
}
}
There is something unbasic about the jar setup, such that I cannot simply create an object, the Info, which I don't have more information about, seems to be the problem. I thought it was a type of Java type? But, I couldn't find anything, so it must be a user create/enumerated type.
Any help to be able to develop this code in a TDD way, instead of just hacking in the derived class is my goal.
The above code will compile (not have errors in eclipse), but it returns NullPointerException: cannot invoke "jarPackageImports.Info.getScene()" because "this.info" is null.
If my understanding is correct, that means that I am not passing or setting up the info variable as it's supposed to be.
Normally you have to use an instance of your Class you want to test.
package jimmy.kilmer.com;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
class GameKITest {
private GameKI gameKi = new GameKI(new Info());
#Test
void getName() {
String actual = gameKi.getName();
assertEquals("Usain Bolt", actual);
}
}
If you can not create an instance of needed dependencies, you could mock It by Mockito.
package jimmy.kilmer.com;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
#ExtendWith(MockitoExtension.class)
class GameKITest {
#Mock
private Info info;
private GameKI gameKi = new GameKI(info);
#Test
void getName() {
Mock.when(info.getVelocity()).thenReturn(result);
String actual = gameKi.update();
assertEquals("Usain Bolt", actual);
}
}
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() {
...
}
}
I realize there are many many very similar questions. I've been through all of them and I still cannot make my code work.
I have a service defined in my Spring-Boot application, just like this:
#Service
public class FileStorageService {
private final Path fileStorageLocation;
#Autowired
public FileStorageService(final FileStorageProperties fileStorageProperties) {
//FileStorageProperties is a very simple class that right now just holds one String value
this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
.toAbsolutePath()
.normalize();
try {
Files.createDirectories(fileStorageLocation);
} catch (IOException e) {
// FileStorageException is my custom, runtime exception
throw new FileStorageException("Failed to create directory for stored files", e);
}
}
}
And I want to test scenario, when directory creation fails and thus I need to mock method Files.createDirectories(). My test class looks like this:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.io.IOException;
import java.nio.file.Files;
#RunWith(PowerMockRunner.class)
#PrepareForTest({Files.class})
public class FileStorageServiceTest {
private static final String UPLOAD_DIR = "uploadDir";
#Test(expected = FileStorageException.class)
public void some_test() throws IOException {
PowerMockito.mockStatic(Files.class);
PowerMockito.when(Files.createDirectories(Mockito.any())).thenThrow(new IOException());
new FileStorageService(createFileStorageProperties());
}
private FileStorageProperties createFileStorageProperties() {
final FileStorageProperties fileStorageProperties = new FileStorageProperties();
fileStorageProperties.setUploadDir(UPLOAD_DIR);
return fileStorageProperties;
}
}
I believe I followed every step from tutorials and questions I've read.
I use:
#RunWith(PowerMockRunner.class),
#PrepareForTest({Files.class}),
PowerMockito.mockStatic(Files.class),
and PowerMockito.when(Files.createDirectories(Mockito.any())).thenThrow(new IOException());.
Still, no exception is thrown during test and it fails. WIll be super thankful for the help, cause I feel I miss something really simple and just cannot see it.
From: https://github.com/powermock/powermock/wiki/Mock-System
Normally you would prepare the class that contains the static methods (let's call it X) you like to mock but because it's impossible for PowerMock to prepare a system class for testing so another approach has to be taken. So instead of preparing X you prepare the class that calls the static methods in X!
Basically, we mock the class's use of the System class, rather than unmockable System class itself.
#PrepareForTest({Files.class})
An alternative, non-Powermock way to do this without mocking any system class would be to create a helper method, #Spy the original class, and mock that helper method specifically to throw the exception.
when(spy.doSomethingWithSystemClasses()).thenThrow(new Exception("Foo");
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!!
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.