Using different mocks in different states Pact provider in Dropwizard - java

I'm trying to set up a pact provider with an application running Dropwizard but I'm having trouble using different mocks for different states. Is there an equivalent to Spring's #MockBean in Dropwizard or some other way to achieve this in Dropwizard?
This is my Provider class:
#RunWith(PactRunner.class)
#Provider("my-proxy")
#PactFolder("src/test/java/pact/pacts")
public class UserContractTest {
private static final String CONFIG_PATH = ResourceHelpers.resourceFilePath("config.yml");
// I want to do the commented out code in Dropwizard with Dropwizard equivalents
// #MockBean
// private MyClass myMockedClass;
#ClassRule
public static final DropwizardAppRule<MyAppConfiguration> RULE =
new DropwizardAppRule<>(MyAppMock.class, CONFIG_PATH);
#TestTarget
public final Target target = new HttpTarget(RULE.getLocalPort());
#State("default")
public void toDefaultState(Map<String, String> params) {
if(params.get("someState").equals("stateOne")) {
// when(myMockedClass.someFunc()).thenReturn("someAnswerForStateOne");
} else {
// when(myMockedClass.someFunc()).thenReturn("someAnswerForAllOtherStates");
}
}
}

I ended up using argThat on the request params to be able to use two different method mocks on the same method.
public class MyAppMock extends MyApp {
#Override
protected UserProvider getUserProvider(Config config) {
var myServiceMock = mock(UserProvider.class);
var userResponseType = new UserResponseType();
var user = new User();
user.setName("Lisa");
user.setAge(30);
userResponseType.setUser(user);
doReturn(userResponseType)
.when(myServiceMock)
.createUser(argThat(createUserRequestType -> createUserRequestType.getName().equals("Lisa")), any());
var errorMessage = "Error";
doThrow(new SomeException(errorMessage, SC_NOT_FOUND))
.when(myServiceMock)
.createPaymentOrder(argThat(createUserRequestType -> createUserRequestType.getName().equals("John")), any());
return myServiceMock;
}
}

Related

How do I use JUnit 5 with testcontainers in a custom network?

I can't seem to get the following the following scenario to work. I am trying to create a scenario
where two containers talked with each other on a separate network using JUnit 5 constructs.
#Testcontainers
class TestContainerTests {
#BeforeAll
static void setup() {
networkName = RandomStringUtils.randomAlphabetic(20);
network =
Network.builder()
.createNetworkCmdModifier(
createNetworkCmd -> {
createNetworkCmd.withName(networkName);
})
.build();
}
private static String networkName;
private static Network network;
#Container
private static GenericContainer<?> whoami =
new GenericContainer<>("containous/whoami")
.withNetwork(network)
.withNetworkAliases("whoami")
.withExposedPorts(80)
.waitingFor(Wait.forLogMessage(".*Starting up on port 80.*", 1));
/**
* An alpine container that is set to sleep. this is used for testing a specific scenario
*/
#Container
private GenericContainer<?> alpine =
new GenericContainer<>("alpine")
.withCommand("sleep 600")
.withNetwork(network);
#Test
void testWhoAmI() {
final var url =
UriComponentsBuilder.newInstance()
.scheme("http")
.host("localhost")
.port(whoami.getMappedPort(80))
.toUriString();
final var responseBody =
WebTestClient.bindToServer()
.baseUrl(url)
.build()
.get()
.uri("/")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.returnResult()
.getResponseBody();
assertThat(responseBody).contains("GET / HTTP/1.1");
}
#Test
void connection() throws Exception {
// this fails connection
final var wget = alpine.execInContainer("wget", "-qO-", "http://whoami/");
System.err.println(wget.getStderr());
assertThat(wget.getStdout()).contains("GET / HTTP/1.1");
}
}
I am aware I can simply manage the lifecycle myself using #BeforeAll and #AfterAll, but I am looking for a way to get it working with the existing annotations.
Using the default methods from Testcontainers for creating networks (outside of #BeforeAll lifecycle methods) should already work for you:
https://www.testcontainers.org/features/networking/#advanced-networking
#Testcontainers
class TestContainerTests {
private static Network network = Network.newNetwork();
// ...
}

How to write unit test for URI create in java

Below is the method I'm trying to write unit test using junit 5
#Value("${proxy.host}")
private String endpoint;
public Request<Void> setAwsRequestGETParameter(String setStatusPath) {
Request<Void> requestAws = new DefaultRequest<Void>("sts");
requestAws.setHttpMethod(HttpMethodName.GET);
requestAws.setEndpoint(URI.create(endpoint));
requestAws.setResourcePath(setStatusPath);
return requestAws;
}
Below is the unit test I'm trying to run
#InjectMocks
private AWSAuthHandler testAWSAuthHandler;
#Test
public void testSetAwsRequestGETParameter() throws Exception {
URI mockedURI = Mockito.mock(URI.class);
assertNotNull(testAWSAuthHandler.setAwsRequestGETParameter("/status/7deaed5e-3080-45ec-89ba-403977d60c0c"));
}
Below is the stack trace:
java.lang.NullPointerException
at java.base/java.net.URI$Parser.parse(URI.java:3106)
at java.base/java.net.URI.<init>(URI.java:600)
at java.base/java.net.URI.create(URI.java:881)
Can someone please help me with the missing part? Thank you
For setting properties of class that you can't mock you can use Spring Reflection Utils, like that:
ReflectionUtils.setField(field, target, value);
where the field is the name of the field which you want to set ("endpoint" for your case),
target is the mocked class (testAWSAuthHandler for your case)
value is the wanted value
As Sweta Sharma said, you need to initialise AWSAuthHandler with some value for endpoint field. That's why it is better to use constructor injection rather than field one.
Assuming your AWSAuthHandler class look like this (as you didn't provide the code for the whole class):
public class AWSAuthHandler {
#Value("${proxy.host}")
private String endpoint;
public Request<Void> setAwsRequestGETParameter(String setStatusPath) {
Request<Void> requestAws = new DefaultRequest<Void>("sts");
requestAws.setHttpMethod(HttpMethodName.GET);
requestAws.setEndpoint(URI.create(endpoint));
requestAws.setResourcePath(setStatusPath);
return requestAws;
}
You can refactor it in the following way:
public class AWSAuthHandler {
private String endpoint;
public AWSAuthHandler(#Value("${proxy.host}") String endpoint) {
this.endpoint = endpoint;
}
public Request<Void> setAwsRequestGETParameter(String setStatusPath) {
Request<Void> requestAws = new DefaultRequest<Void>("sts");
requestAws.setHttpMethod(HttpMethodName.GET);
requestAws.setEndpoint(URI.create(endpoint));
requestAws.setResourcePath(setStatusPath);
return requestAws;
}
Then you can create tests for this class:
private AWSAuthHandler testAWSAuthHandler;
#BeforeEach
void setUpTests() {
this.testAWSAuthHandler = new AWSAuthHandler("some-endpoint-here");
}
#Test
public void testSetAwsRequestGETParameter() throws Exception {
assertNotNull(testAWSAuthHandler.setAwsRequestGETParameter("/status/7deaed5e-3080-45ec-89ba-403977d60c0c"));
}
You can read more about Spring #Value annotation here, for example: https://www.baeldung.com/spring-value-annotation

Creating an annotation for JUnit 4/5 to initialize and inject an object in tests

I am developing a testing library for Kafka, Kafkaesque. The library lets you develop integration tests for Kafka using a fluid and elegant (?!) API. For now, I develop the version for Spring Kafka.
The library needs to be initialized in every test:
#Test
void consumeShouldConsumeMessagesProducesFromOutsideProducer() {
kafkaTemplate.sendDefault(1, "data1");
kafkaTemplate.sendDefault(2, "data2");
new SpringKafkaesque(broker)
.<Integer, String>consume()
.fromTopic(CONSUMER_TEST_TOPIC)
.waitingAtMost(1L, TimeUnit.SECONDS)
.waitingEmptyPolls(5, 100L, TimeUnit.MILLISECONDS)
.withDeserializers(new IntegerDeserializer(), new StringDeserializer())
.expecting()
.havingRecordsSize(2)
.assertingThatPayloads(Matchers.containsInAnyOrder("data1", "data2"))
.andCloseConsumer();
}
Instead of manually initializing the SpringKafkaesque object, I want to create an annotation that does the magic for me. Something like the #EmbeddedKafka annotation of Spring Kafka.
#SpringBootTest(classes = {TestConfiguration.class})
#Kafkaesque(
topics = {SpringKafkaesqueTest.CONSUMER_TEST_TOPIC, SpringKafkaesqueTest.PRODUCER_TEST_TOPIC})
class SpringKafkaesqueTest {
#Autowired
private Kafkaesque kafkaesque;
#Test
void consumeShouldConsumeMessagesProducesFromOutsideProducer() {
kafkaTemplate.sendDefault(1, "data1");
kafkaTemplate.sendDefault(2, "data2");
kafkaesque
.<Integer, String>consume()
.fromTopic(CONSUMER_TEST_TOPIC)
.waitingAtMost(1L, TimeUnit.SECONDS)
.waitingEmptyPolls(5, 100L, TimeUnit.MILLISECONDS)
.withDeserializers(new IntegerDeserializer(), new StringDeserializer())
.expecting()
.havingRecordsSize(2)
.assertingThatPayloads(Matchers.containsInAnyOrder("data1", "data2"))
.andCloseConsumer();
}
Is it possible? Any suggestion?
JUnit 4
One possible solution is to create a custom annotation processing using reflection. You can get the test method name with #Rule, so for example:
public class CustomAnnotationTest {
private SpringKafkaesque kafkaesqueInstance;
#Rule
public TestName testName = new TestName();
#Before
public void init() {
Method method = null;
try {
method = this.getClass().getMethod(testName.getMethodName());
} catch (Exception ex) {
// handle exceptions
}
if (method.isAnnotationPresent(EmbeddedKafka.class)) {
// Init your SpringKafkaesque instance here
// kafkaesqueInstance = new SpringKafkaesque(broker)
//
}
}
#EmbeddedKafka
#Test
public void testCustomAnnotated() {
// your test here
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface EmbeddedKafka {
}
}
You need to store this instance in the class-level variable. For the methods with no #EmbeddedKafka annotation, this variable will be null.
JUnit 5
With JUnit 5 you may consider using parameter injection with ParameterResolver. First of all, you need to implement this interface:
public class KafkaesqueResolver implements ParameterResolver {
#Override
public boolean supportsParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) throws ParameterResolutionException {
return parameterContext.getParameter().getType() == SpringKafkaesque.class;
}
#Override
public Object resolveParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) throws ParameterResolutionException {
// Create an instance of SpringKafkaesque here and return it
return new SpringKafkaesque();
}
}
Next, add #ExtendWith(KafkaesqueResolver.class) annotation to your test class, and add a parameter to your test method, where you need the instance of SpringKafkaesque:
#ExtendWith(KafkaesqueResolver.class)
public class ParamInjectionTest {
#Test
public void testNoParams() {
// nothing to inject
}
#Test
public void testWithParam(SpringKafkaesque instance) {
// do what you need with your instance
}
}
No custom annotation required in this case.

Test the service in springboot

This is the service I have :
#Service
public class UserInfoService {
#Autowired
private UserInfoServiceClient UserInfoServiceClient; // Call another Rest API
public ResponseEntity<ResponseUserInfoData> sendUserInfo(String UserId) throws RuntimeException {
ResponseUserInfoData responseUserInfoData = new ResponseUserInfoData();
//Get the body from the User service client
UserServiceDTO UserServiceDTO = UserInfoServiceClient.sendResponse(UserId).getBody();
//Set the values of responseUserInfoData
Optional<UserServiceDTO> UserServiceDTOOptional = Optional.ofNullable(UserServiceDTO);
if (UserServiceDTOOptional.isPresent()) {
UserServiceDTOOptional.map(UserServiceDTO::getId).ifPresent(responseUserInfoData::setid);
}
else return ResponseEntity.noContent().build();
}
}
I have to test it. I'm new to JUnit testing. I want to test the following points:
To check if the service return the response entity
To check if the get and set method works
This is what I started?
#RunWith(MockitoJUnitRunner.class)
public class ServiceTests {
#InjectMocks
private UserInfoService UserInfoService;
#Mock
private UserInfoServiceClient UserInfoServiceClient;
#Mock
private UserServiceDTO UserServiceDTO;
#Test
public void shouldReturnUserInfoData() throws IOException{
UserInfoService.sendUserInfo("ABC");
}
}
Any help is appreciated?
Mockito is useful to mock the dependencies of the service so that you can test all the code path in you service. In your case you will want to stub the call to serInfoServiceClient.sendResponse(UserId) and have it return a specific UserServiceDTO for each test case.
The test file looks like it is set up correctly, you only need to mock the method to give you the result you need for the particular test, for example
#RunWith(MockitoJUnitRunner.class)
public class ServiceTests {
#InjectMocks
private UserInfoService UserInfoService;
#Mock
private UserInfoServiceClient UserInfoServiceClient;
#Test
public void shouldReturnUserInfoData() throws IOException{
final String userId = "123";
// The mocked return value should be set up per test scenario
final UserServiceDto dto = new UserServiceDto();
final ResponseEntity<UserServiceDTO> mockedResp = new ResponseEntity<>(dto, HttpStatus.OK);
// set up the mock service to return your response
when(UserInfoServiceClient.sendResponse(userId)).thenReturn(mockedResp);
// Call your service
ResponseEntity<ResponseUserInfoData> resp = UserInfoService.sendUserInfo(userId);
// Test the result
Assert.isNotNull(resp);
}
}
There are also other ways to mock the dependencies using Mockito. I suggest going through the quick start of https://site.mockito.org/

How to create a Form<T> for a play (java) unit test now that Form.form() is deprecated?

In application code when dealing with forms it is recommended to use a FormFactory to create a Form wrapper around the form of type T. But when it comes to testing, what is the way to create a Form? (Do you have to inject FormFactory in the test?)
My app does something similar to that:
class MyAmazingClass {
private final FormFactory formFactory;
#Inject
MyAmazingClass(FormFactory formFactory) {
this.formFactory = formFactory;
}
public CompletionStage<Result> myAmazingMethodHandlingForms() {
Form<String> form = formFactory.form(String.class).bindFromRequest();
// ... Actually doing something
return null;
}
}
What shall my test class (for unit testing) looks like?
I am trying something like this but I think I should not try to inject the FormFactory (also it does not seems to work):
public class MyAmazingClassTest extends WithApplication {
#Mock
FormFactory mockedFormFactory;
#Inject
FormFactory realFormFactory;
MyAmazingClass myAmazingClass;
#Override
protected Application provideApplication() {
return new GuiceApplicationBuilder().build();
}
#Before
public void setUp() throws Exception {
myAmazingClass = new MyAmazingClass(mockedFormFactory);
}
#Test
public void testMyAmazingMethodHandlingForms() throws Exception {
String myString = "ciao";
Form<String> stringForm = realFormFactory.form(String.class).fill(myString);
when(mockedFormFactory.form(eq(String.class)).bindFromRequest()).thenReturn(stringForm);
myAmazingClass.myAmazingMethodHandlingForms();
// Some assertions...
}
}
I am using JUnit 4, Java 8 and Play framework 2.5.
I would say that mixing mocks with the real application is not the best idea here. You should either use mocks (and avoid WithApplication), or you can use the "real" instances by calling app.injector().instanceOf() (including for your MyAmazingClass). For example, when only using mocks:
public class MyAmazingClassTest {
#Test
public void testMyAmazingMethodHandlingForms() throws Exception {
Form<String> form = mock(Form.class);
// setup the mocked form as you expect it to behave
FormFactory formFactory = mock(FormFactory.class);
when(formFactory.form(eq(String.class)).bindFromRequest()).thenReturn(form);
MyAmazingClass myAmazingClass = new MyAmazingClass(formFactory);
myAmazingClass.myAmazingMethodHandlingForms();
// Some assertions...
}
}
Testing using the real instances would requires you to do a request, since apparently, you are binding from the request:
public class MyAmazingClassTest extends WithApplication {
#Test
public void testMyAmazingMethodHandlingForms() throws Exception {
Map<String, String> formData = new HashMap<>();
formData.put("some", "value");
// fill the form with the test data
Http.RequestBuilder fakeRequest = Helpers.fakeRequest().bodyForm(formData).method(Helpers.POST);
Result result = Helpers.route(app, fakeRequest);
// make assertions over the result or something else.
}
}

Categories