How to do parallel wire mock test execution having dynamic stubbing through json files - wiremock

I am currently running a single test case with wire mock. Following is the code snippet:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class, webEnvironment = DEFINED_PORT)
public class ResolveIT {
#ClassRule
public static WireMockRule wireMockRule = new WireMockRule(8900);
#Autowired
private TestRestTemplate restTemplate;
#BeforeClass
public static void init() {
wireMockRule.resetAll();
}
#Test
public void testA() {
HttpEntity<String> entity = new HttpEntity<String>(null, getRequestHeaders());
ResponseEntity<String> response = restTemplate.exchange(localhost:8080/abc, HttpMethod.GET, entity, String.class);
assertEquals(response.getStatusCode(), HttpStatus.OK);
assertEquals(response.getBody(), "Hey");
}
}
I have placed my stubs in a json file in mappings folder which looks like this:
{
"request": {
"method": "GET",
"url": "/abc/xyz"
},
"response": {
"status": 200,
"bodyFileName": "body.json",
"headers": {
"Content-Type": "application/text",
}
}
}
I run this class as JUnit tests from my IDE. Now I need help with the following scenario:
I wish to run a test suite where multiple classes having such tests will run in parallel, in short, I wish to run wiremock tests in parallel. If I configure all my classes like this, I will have to provide a different port to make them run in parallel which doesnt seems to be a
feasible solution here. Also I read somewhere that wiremock is not thread safe.
How can I make the run thread safe?
How can I configure my code so that wiremock runs on one port and all my tests can run in parallel? What should be code for that and how should that single instance of wiremock be configured and how the test should be run?
To achieve this do I need to make the stubbing manually in each test class or can it be achieved along with dynamic stubbing through json file?
P.S. - I am using maven in my project if it is required to be known.

Related

ConditionTimeout of async tests when using wiremock

I have one instance of wiremock that is used across multiple test classes, It has worked fine until recently, when used to test
async methods, when the test classes are ran singly, tests pass but when the entire tests are ran(mvn test), some of the async class tests fail with
ConditionTimeOut error. The verify is failing because, I presume, the wiremock server was not done when the verify was called and the awaitility library is
waiting for it. Just my understanding based on this links -->
https://github.com/tomakehurst/wiremock/issues/565
https://github.com/tomakehurst/wiremock/issues/574
here is my wiremock class def :
#ExtendWith(SpringExtension.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureWireMock(port = 9099)
public class WireMockTest {
#Autowired
public wireMockClassA wireMockClassA;
#Autowired
public wireMockClassB wireMockClassB;
//other definitions here and more wiremock class...
}
here is an example test async class:
public class SaleWireMockTest extends WireMockTest {
#Test
void call_sale_endpoint_and_return_200() {
wireMockClassA.callSaleEndpoint(PATH, request, HttpStatus.OK);
makeAsyncCall();
await().atMost(1, TimeUnit.SECONDS).untilAsserted(() ->
wireMockClassA.verify(1, request));
}
//more test methods here....
}
stack:
java 14
wiremock 2.26.2
Spring boot 2.3.2.RELEASE
Have you tried setting the first poll time?
await().pollDelay(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(3)).untilAsserted(() -> {...});

SpringBoot Test Cases not working in the way they were expected to

I have been working on a basic Spring Boot Application building REST APIs. I have learnt to write the APIs and now I am trying to write Unit Tests for them. I have written one unit test for the get API and one for the post API. The post API test seems to be running fine but the get api test fails. I am not sure why. I am not sure if the get test is running before the post and hence nothing is available so it fails?
I have tried changing the order in which the tests are written in order to see the execution order changes but it hasn't changed.
#RunWith(SpringRunner.class)
#WebMvcTest(value = ProjectRestController.class)
public class ProjectControllerTest
{
private String baseURL = "http://localhost:8080/";
private String expectedResult = "{id:0, name:\"Testing Course 0\", description: \"This is a test for course 0\"}";
#Autowired
private MockMvc mockMvc;
#MockBean
private ProjectService projectService;
Project mockProject = new Project(0, "Testing Course 0", "This is a test for course 0");
#Test
public void addProject() throws Exception
{
mockMvc.perform(MockMvcRequestBuilders.post(baseURL+"/projects")
.content(asJsonString(new Project(0, "Test 0", "Testing Project 0")))
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
//This test does not seem to work. Returns 404
#Test
public void getProject() throws Exception
{
mockMvc.perform(MockMvcRequestBuilders.get(baseURL+"/projects/0")
.accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
}
public static String asJsonString(final Object obj)
{
try
{
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
I expected a status 200 from the GET as the post is working fine however the get returns a 404.
The issue is due to you have a base URL you should not send the base URL, pass only /project/0

How to write integration tests for spring-batch-integration?

I'm using spring-integration bundled with spring-batch and got stuck trying to write integration tests to test the whole flow, not just single config.
I've created Embedded Sftp Server for this tests and trying to send message to sftpInboundChannel - the message is sent, but nothing happens, but when i send this message to the next channel (after sftpInboundChannel) it goes ok. Also i'm not able to load test source properties, even though i'm using #TestPropertySource annotation.
This are my class annotations
#TestPropertySource(properties = {
//here goes all the properties
})
#EnableConfigurationProperties
#RunWith(SpringRunner.class)
#Import({TestConfig.class, SessionConfig.class})
#ActiveProfiles("it")
#SpringIntegrationTest
#EnableIntegration
#SpringBootTest
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
This is my class body
#Autowired
private PollableChannel sftpInboundChannel;
#Autowired
private SessionFactory<ChannelSftp.LsEntry> defaultSftpSessionFactory;
#Autowired
private EmbeddedSftpServer server;
#Test
public void shouldDoSmth() {
RemoteFileTemplate<ChannelSftp.LsEntry> template;
try {
template = new RemoteFileTemplate<>(defaultSftpSessionFactory);
SftpTestUtils.moveToRemoteFolder(template);
final List<ChannelSftp.LsEntry> movedFiles = SftpTestUtils.listFilesFromDirectory("folder/subfolder", template);
log.info("Moved file {}", movedFiles.size());
final MessageBuilder<String> messageBuilder = MessageBuilder.withPayload("Sample.txt") // path to file
.setHeader("file_Path", "Sample.txt")
boolean wasSent = this.sftpInboundChannel.send(messageBuilder.build());
log.info("Was sent to sftpInboundChannel channel {}", wasSent);
log.info("message {}", messageBuilder.build());
} finally {
SftpTestUtils.cleanUp();
}
}
To the case of not read the property file one solution is add in your Test class something like this:
#BeforeClass
public static void beforeClass() {
System.setProperty("propertyfile", "nameOfFile.properties");
}
A second way is to create a xml (or class) config where you add the tag:
<context:property-placeholder
location="nameOfFile.properties"
ignore-resource-not-found="true" system-properties-mode="OVERRIDE" />
and your file will be localized.
The property file should be inside of resources folder.

SpringbootTest + TestContainers: how do I refresh the database after tests pollute the database

I am using an abstract class like this:
#SpringBootTest(classes = MyAppApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
#ActiveProfiles("test")
public abstract class AbstractIntegrationTest {
static {
PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer().withPassword("password")
.withUsername("postgres").withDatabaseName("MyApp");
postgreSQLContainer.start();
System.setProperty("spring.datasource.url", postgreSQLContainer.getJdbcUrl());
System.setProperty("spring.datasource.password", postgreSQLContainer.getPassword());
System.setProperty("spring.datasource.username", postgreSQLContainer.getUsername());
}
Then I have many tests that leverage that use that class like this:
public class moreTests extends AbstractIntegrationTest {
TestRestTemplate restTemplate = new TestRestTemplate("my-user", "password");
HttpHeaders headers = new HttpHeaders();
#Test
public void SimpleHealthCheck() {
HttpEntity<String> entity = new HttpEntity<String>(null, headers);
ResponseEntity<String> response = restTemplate.exchange(
createURLWithPort("/api/v1/healthcheck"),
HttpMethod.GET, entity, String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
#Test
public void GetInst() {
HttpEntity<String> entity = new HttpEntity<String>(null, headers);
ResponseEntity<String> response = restTemplate.exchange(
createURLWithPort("/api/v1/institutions"),
HttpMethod.GET, entity, String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
However, some of my tests will pollute the database. I'd like to control if a test runs with a fresh database or not. What's the prescribed way to do this?
After more reading about Spring boot integration testing, it appears the prescribed way is to use the "#DirtiesContext" annotation for tests that are destructive (or dirty).
EDIT: After a few months, I realized #DirtiesContext is not awesome. It basically resets the whole app which can be expensive. Also, #DirtiesContext May not reset your database in some cases depending on how your app works. I suggest having a cleanup SQL script that runs in your #BeforeAll or #AfterAll section of each test class. This cleanup SQL script needs to be carefully written.
you either use the #Before annotation to clean everything before executing your tests.
Or you clean in each test before you execute.
Each test should be independent from the other. So usually:
clear and set up expectations
run test
If test fails, your database will be in the failed state so you can check what happened.

Use parameters in beforeclass in Junit

What I wan to do is read parameterized values and use them in the before class to set up a webdriver for the bowser as soecified by the parameter, the run the tests in the browser. Then get the next browser and run the test in that browser and so on for all the other specified browsers. But I am getting null values in the before class for the parmeters. Can you do this in Junit or is there another way of doing this?
Thanks
#RunWith(value = Parameterized.class)
public class MultiBrowser {
private static WebDriver driver;
private static String browser;
//private static Dimension device;
private static String testData = "Testing";
private static String device;
#Parameters
public static Collection< Object[]> data() {
System.out.println("Inside parameter");
return Arrays.asList(new Object[][]{{"Firefox", "IPHONE4"},{"Chrome", "IPAD"},{"Ie", "SamsungGalaxy"}});
}
public MultiBrowser(String browser, String device){
System.out.println("Inside MultiBrowser = "+ browser+" " + device);
this.browser=browser;
this.device=device;
}
#BeforeClass
public static void dosetUp() throws Exception {
System.out.println("Doing setup before class..." + browser + device);
}
The technique you're using here won't work. #Parameters are injected through constructors, but your static #BeforeClass method is invoked before any constructor has been called, so those static fields will be null.
Your question is very similar to Creating a JUnit testsuite with multiple instances of a Parameterized test, and also Parameterized suites in Junit 4?; both answers suggest TestNG as a framework that is able to do this.
In JUnit, you could use the technique suggested by
How do I Dynamically create a Test Suite in JUnit 4?
to build a test suite dynamically and make do without using #Parameters.
Or, for a simpler but less efficient solution, move your setup code into a non-static #Before method and accept that it will run before every single test.