Rest Assured & Spring - Value Becomes Null After First Test - java

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() {
...
}
}

Related

How do I create an object from a derived class in Junit for testing

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);
}
}

PowerMock won't mock static method to throw an Exception in a Spring-Boot application

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");

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.

PowerMock: Mocking static method that affect one test only

My situation:
I would like to add a new test. And I need to mock one static method X of Service class.
Unfortunately existing tests are using this static method in some way.
And when I mock X method using PowerMock then other test failed.
What is more I shouldn't touch other tests.
Is there any opportunity to mock static methods for one test only? ( using PowerMock).
Thanks in advance.
Sure, it is possible! The only time when you could run into problems is if you are trying to test multiple threads at the same time... I put an example of how to do it below. Enjoy.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
#RunWith(PowerMockRunner.class)
#PrepareForTest(IdGenerator.class)
public class TestClass {
#Test
public void yourTest()
{
ServiceRegistrator serTestObj = new ServiceRegistrator();
PowerMock.mockStatic(IdGenerator.class);
expect(IdGenerator.generateNewId()).andReturn(42L);
PowerMock.replay(IdGenerator.class);
long actualId = IdGenerator.generateNewId();
PowerMock.verify(IdGenerator.class);
assertEquals(42L,actualId);
}
#Test
public void unaffectedTest() {
long actualId = IdGenerator.generateNewId();
PowerMock.verify(IdGenerator.class);
assertEquals(3L,actualId);
}
}
TestClass
public class IdGenerator {
public static long generateNewId()
{
return 3L;
}
}
The easiest way to solve your problem is create new test class and place your tests there.
You can also wrap up this static class with normal class hidden behind interface in your code and stub this interface in your tests.
Last thing you can try is to stub each method of your static class in #SetUp method using:
Mockito.when(StaticClass.method(param)).thenCallRealMethod();
and stub particular method in your test using:
Mockito.when(Static.methodYouAreInterested(param)).thenReturn(value);
For those looking to achieve this using Mockito with PowerMocks, this can be done by adding the #PrepareForTest annotation to the tests themselves that need to mock out the values instead of the test class itself.
In this example, let's pretend there is SomeClass that has a static function (returnTrue()) that always returns true like so:
public class SomeClass {
public static boolean returnTrue() {
return true;
}
}
This example shows how we can mock out the static call in one test and allow the original functionality to stay the same in another.
#RunWith(PowerMockRunner.class)
#Config(constants = BuildConfig.class)
#PowerMockIgnore({"org.mockito.*", "android.*"})
public class SomeTest {
/** Tests that the value is not mocked out or changed at all. */
#Test
public void testOriginalFunctionalityStays()
assertTrue(SomeClass.returnTrue());
}
/** Tests that mocking out the value works here, and only here. */
#PrepareForTest(SomeClass.class)
#Test
public void testMockedValueWorks() {
PowerMockito.mockStatic(SomeClass.class);
Mockito.when(SomeClass.returnTrue()).thenReturn(false);
assertFalse(SomeClass.returnTrue())
}
}

Categories

Resources