Spring Cloud Contract generates message verifier test from Groovy to YAML - spring-boot

Currently I'm using Spring Cloud Contract to test my publishing of events from one microservices to another. After the test run succesfully, I would publish the stubs to be use by other microservices.
In the publisher microservice, I write a Groovy test with Contract.make and specify the input and outputMessage like below.
input {
triggeredBy "triggerEventMethod()"
}
outputMessage {
sentTo "somewhere"
body """
{
"field": "sampleData"
}
"""
headers {
header("contentType", applicationJson())
header("eventName", "SampleEventName")
}
}
In my BaseClass, I annotated the class with #ImportAutoConfiguration(NoOpContractVerifierAutoConfiguration::class) to configure the MessageVerifier and declare my triggerEventMethod() to run some method which would trigger the ApplicationContext to publish the SampleEventName. I have my own custom implementation class of MessageVerifierReceiver which would listen to the SampleEventName and store the message in a ThreadLocal then my override of the receive method just try to retrieve the message available in the ThreadLocal. Then the generated test by spring-cloud-contract would just verify the content of the body and headers of the event.
As far as it goes, this test has been working for more than 2 years and currently after upgrading spring-cloud-contract from 2.2.3.RELEASE to 3.1.1, I'm experiencing errors while running the generated test.
My observation on the newly generated version of test is that it would generate a YAML version of my Groovy contract and place it relatively with the generated test class in generated-test-sources folder. When running the test, it would try to reference the .yml file and hit FileNotFoundException of the .yml file. I try manually remove the the logic where it look for the file and my test case would pass after that, but since it is a generated test, it technically should not be edited this way. Sample referencing of the .yml file as below.
ContractVerifierMessage response = contractVerifierMessaging.receive("somewhere",
contract(this, "sampleEvent.yml"));
Does anyone know any way which I could exclude the generation of .yml or referencing of the YAML contract in my generated test? Or if you have better suggestions of how I could refactor my test of ensuring applicationContext publishing works?
The Groovy files are then generated to stubs for my other microservices to do contract testing and serve as mock data.

Related

Integration Test a Reactive Spring Cloud Stream

TLDR; How do you test a Reactive Function composition using the Test Binder?
I have a Spring Cloud Stream that uses Reactive Functions and I don't know how to test it. I don't see any official docs on how to do an Integration Test from input source to output destination binder.
In my specific case, I am connecting a Spring Integration flow using a Reactive Supplier and the IntegrationReactiveUtils.messageChannelToFlux() pattern. This works in a development environment - I can pull messages from RabbitMQ using the Spring Integration Flow and they enter the SCSt.
My SCSt has several function chained together, each one is reactive. They are composed like func1|func2|func3. I verified this works with a dev Rabbit (source) and Kafka (Destination).
I can't seem to figure out how to test this, and there doesn't seem to be any official documentation on testing a complete reactive stream. Right now I have code that roughly looks like this:
#Autowired
MessageChannel inputChannel;
#Autowired
private OutputDestination output;
#Test
void myTest() {
//omitted prep of var 'messageToSend'
this.inputChannel.send(messageToSend);
var outputMessage = output.receive(5000);
Assertions.assertNotNull(outputMessage.getPayload());
}
The error I receive is that output.receive(5000) returns null. I suspect a threading issue because I am not subscribing to the Flux and waiting for completion.
I have run a debugger in the Flux functions and see the message going all the way to the end with no errors or weirdness.
I figured this out actually. I had to specify the binder name. I had a test property spring.cloud.stream.bindings.processingStream set, which I thought made 2 new bindings (processingStream-in-0 and processingStream-out-0).
It turns out I had to set the binding name in the test code like output.receive(5000, "processingStream"), without the -out-0 suffix. I can now receive messages from the stream.

Launch spring boot mvc test from custom testng framework

Where I'm working one of our customer required to use a custom test framework written using testng that allows to handle different parameters and test iterations using excel files.
This framework uses a main class to handle all the tests, lets call it TestManager.
This TestManager defines all the #Before and #After operations and has a method called exec() which is annotated as #Test.
This method is used to call the different components required from the test, these components are java classes that implements a single method exec() containing the logic of the single component.
public class TestManager {
// ... Before, After methods
#Test(
dataProvider = "..."
)
public void exec(Parameter[] inParameter) {
// load parameters...
foreach component:
component.exec()
}
}
public class ComponentXYZ {
public void exec() {
// load input params
// Call a microservice and get results, find value on db, selenium operations...
// unload output params for next components
}
}
This framework was designed to be used with selenium, or to test microservices using some http request library and is contained in a standalone module.
So my project has:
A spring boot module
A test module which (in my idea) should have a dependency over the spring boot module
Given this situation do you think it could be possible to use WebMvcTest to perform integration tests while using this custom framework?
I've been trying for a while but I'm always getting errors or I'm not able to #Autowire MockMvc, I can't seem to start a minimal spring boot instance directly from this test framework...
I don't think running my spring boot app and calling the microservices using http is the correct way to test but at this moment is the only thing it's working.

How to put together two application.yml configs of two projects?

I have two projects. One is just a client¹ that does http request to an external service. The other is a Rest API.
The client¹ reads an url configured in its own application.yml, but when I add a dependency (through pom.xml) to this client in the Rest API project, it no longer reads that property (it is null).
I want it to read from its own application.yml, so that I have a default value (that can be overridden later if necessary). How can I do that?
¹ The client is defined like this:
#Component
#ConfigurationProperties("app.client.notification")
public class NotificationClient {
private String url; // comes from application.yml.
// Works fine in the client project,
// and DOESN'T in the Rest project
}
You need to explicitly define the location of that .yml file somewhere in the code a'la #PropertySource("classpath:/application.yml"). I don't know about naming conflicts though, you need to experiment with it yourself.

Best way to mock complex soap responses

I have a Java method I want to Unit test, but it requires a mocked SOAP response which contains multiple lists and layers of nodes. I am doing this with a handwritten mock i.e. just manually creating the objects and setting the values, but as the response is quite complex its a pain building up the response. I have a sample XML response is there an easy way of creating the mock using the XML?
Also I looked at Mockito and it looks fine for simple Objects, but it doesnt seem that good for complex responses (I may not be using it to its full potential).
The app stack is Java 1.6, Spring 3 and using JAX-WS.
I do something like this
#WebService
public class MyWebService {
#Autowired
private ServiceBean serviceBean;
public SomeReturedData getData(SomeInputData inputData) {
return serviceBean.getData(inputData);
}
}
For my UnitTest, I have a mock instanciation of "ServiceBean" which I inject in to #MyWebService, and "MyWebService" is deployed using the "in-vm" transport as described here
By Using the in-vm transport, All the XML marshalling/unmarshalling is still done by the web-service framework ,and you only have to deal with Java part.
Now someone might ask, why not test the "ServiceBean" directly, why the need to deply a WS using in-vm transport ? Well 2 things, Using in-vm transport you get to test that the JAXB XML marshalling/unmarshalling is working correctly, and it also allows you to test any intercepting handlers that you might have defined for your webservice.

Acceptance testing preloading of data into GAE dev server datastore

In my application I have a set of of DAOs which I inject into my application layer. For an acceptance test I'm writing, I want to preload the dev_server datastore with data, so I use the same Spring config in my JUnit test (using the #ContextConfiguration annotation) to inject an instance of the relevant DAO into my test. When I actually go to store some data eg:
dao.add(entity)
I get the dreaded "No API environment is registered for this thread."
Caused by: java.lang.NullPointerException: No API environment is registered for this thread.
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:108)
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:118)
....
This is probably because my test case hasn't read in the GAE application-web.xml with the app details (although I'm guessing here I could really be wrong); so it doesn't know to write to the same datastore that the app running on the dev_server is reading/writing to.
How can I get my test to "point" to the same datastore as the app? Is there some "datasource" mechanism that I can inject both into the app and the test? Is there a way to get my test to force the datastore api to read the needed config?
Here is a page that talks about how to do unit tests that connect to a dev datastore. Is this the kind of thing you're looking for? Basically it talks about two classes, LocalServiceTestHelper and LocalDatastoreServiceTestConfig that you can use to set up an environment for testing. While the example given is for unit tests, I believe it will also work for your situation.
You can then configure things like whether the dev datastore is written to disk or just kept in memory (for faster tests). If you want this data to go to the same place as your dev server, you will probably want to adjust this, as I think the default is the "in memory" option. If you look at the javadoc there is a "setBackingStoreLocation" method where you can point to whatever file you want.
I've found the solution!!!!
For some reason the Namespace, AppID and the AuthDomain fields of the test datastore have to match that of the dev_server, then the dev_server can see the entities inserted by the test.
You can see the values for the environment (dev_server or test code) with the following statements
System.out.println(NamespaceManager.get());
System.out.println(ApiProxy.getCurrentEnvironment().getAppId());
System.out.println(ApiProxy.getCurrentEnvironment().getAuthDomain());
In your instance of LocalServiceTestHelper (eg: gaeHelper), you can set the values for the test environment
// the NamespaceManager is thread local.
NamespaceManager.set(NamespaceManager.getGoogleAppsNamespace());
gaeHelper.setEnvAppId(<the name of your app in appengine-web.xml>);
gaeHelper.setEnvAuthDomain("gmail.com");
Then the dev_server will see your entities. However because of synchronisation issues, if the test writes to the datastore after the dev_server has been started the dev_server wont see it unless it can be forced to reread the file (which I haven't figured out yet). Else the server has to be restarted.
I've found a workaround, although it's not very nice because each test method doesn't clean up the Datastore, as explained in the article Local Unit Testing for Java, however, the Datastore starts clean each time the Test class is run, so it's not so bad, provided that you're careful about that.
The problem is, that when using SpringJUnit4ClassRunner, the spring environment is created before the #Before annotation can be run, the solution is use #BeforeClass and use a static variable for LocalServiceTestHelper, to have them created before the Spring Environment is set up.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:META-INF/spring/context-test.xml")
#Transactional
public class MyTest {
#Inject
private MyService myService;
private static final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
#BeforeClass
public static void beforeClass() {
helper.setUp();
}
#AfterClass
public static void afterClass() {
helper.tearDown();
}
If anyone has a better solution, I'll be glad to hear!

Resources