How to start Spring Boot app without depending on Pivotal GemFire cache - java

I have a Spring Boot app with a Pivotal GemFire ClientCache instance configured and its corresponding domain objects. I am also using Spring Boot Test for unit testing. For every test case execution, either through class or Maven build, Spring ApplicationContext fails to load if the GemFire cache is down.
How to start Spring Boot application without depending on GemFire cache?

I am not sure I follow exactly what you mean by...
"For every test case execution, either through class or Maven build, Spring ApplicationContext fails to load if the GemFire cache is down."
Are you recreating the ClientCache instance for each test case (method) in your test class?
If so, then this can be tricky to do since even after calling ClientCache.close(), GemFire may not have completely "closed" and released all the resources used by the ClientCache instance. However, usually that does not prevent the Spring ApplicationContext from being recreated on subsequent test case executions. It usually just leads to subsequent test failures since the ClientCache instance is dirty, or stale, retaining old state from the previous (or last) test case execution.
Are you also using Spring's #DirtiesContext on your test case method as well?
Usually, it is wise to cycle the ApplicationContext and GemFire cache instance (e.g. ClientCache) per test class, where each test case method in the test class will use the same ApplicationContext and ClientCache instance; this is the most ideal.
With that, I have 2 things to share with you:
First, have a look at the new Spring Boot for Apache Geode/Pivotal GemFire project. Documentation is here. I announced the availability of this project nearly a month ago now. This project takes a "client-side" perspective to building Spring Boot applications with Pivotal GemFire. That is, it gives you an auto-configured ClientCache instance by default.
Specifically, have a look at Spring Boot for Pivotal GemFire's test suite, beginning here. Nearly all these test classes use a ClientCache instance and test various aspects of Pivotal GemFire, such as CQ's or Security, etc.
In certain test classes, I used a "mock" ClientCache instance (for example, this test class, and this test configuration in particular). However, in many other cases, I used a live GemFire ClientCache instance, for example or this test class, which is interesting since this test class even launches a server for the ClientCache instance (the test itself) to connect to.
All the test coordination logic in Spring Boot for Apache Geode/Pivotal GemFire is provided by another new project, Spring Test for Apache Geode/Pivotal GemFire. Unfortunately, Spring Test for Apache Geode/Pivotal GemFire is still largely a WIP, so does not have documentation yet. However, I have used this new test project extensively to test Spring Boot for Apache Geode/Pivotal GemFire. You will see its presence in the extension classes, like ForkingClientServerIntegrationTestsSupport, and so on.
In summary, use the new Spring Boot for Pivotal GemFire & Spring Test for Pivotal GemFire project as your guide for writing more effective Unit and Integration tests.
Finally, if you have an example GitHub repository reproducing your problem, I can help point you in the right direction.
Hope this helps!
Regards,
John

For your unit tests, use a different profile. Say application-ut.yaml and ask spring not to use any cache implementation library:
application-ut.yaml (add below entry and remove whatever implementation u configured for Gemfire)
spring.cache.type : simple

Related

#SpringBootTest Toggable webEnvironment?

I want to toggle the webEnvironment config inside SpringBootTest to support running the tests in a pipeline (where the tests needs to be able to boot the server themselves) and locally (where I want to use a standalone server for faster tests.
Figured having a Profile which I could set would be a good solution to it but SpringBootTest seems to flat out ignore whatever profile I attach at the same level, is it simply too early in Spring's lifecycle for it to pick up profiles? Is there a better way to do this?
#Profile("myProfile")
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) // Starts regardless of what #Profile is
public class MyClass{
...
}
E: Related question:
SpringBootTest enable/disable webEnvironment based on input
E2: After some discussion down below I'm ditching the remote mode, not worth the hassle.
I was wondering why do you even need to rely on spring here? JUnit already has #EnabledIf annotation (documentation), so you can use it to not even attempt to run the test.
In my understanding it's even better, because this will work for all the tests that might even not run spring (unit tests for example). Also it should be better from the performance endpoint (you don't try to even run the Application Context, find/register beans, etc.)

Running the original application from Spring Boot integration test

I have a simple Spring Boot application which reads from Kafka topic and persists the messages to some cache.
I would like to add an integration test, which would launch my original application, generate some messages from embedded Kafka, and then assert cache contents.
I'm struggling with the "launch my original application" part. How does one do that from Spring Boot integration test?
I've tried doing something like that:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = OriginalApplication.class)
#EmbeddedKafka
public class OriginalApplicationIntegrationTest {
#Test
public void test() throws Exception {
...
}
}
But I see no attempts from Spring to launch my original application.
First of all, there are two possible big "areas" that can go wrong:
Spring Boot Test Setup
Kafka Integration
I believe the question is around the first part so I'll concentrate on that part.
For a quick answer:
When you put a #SpringBootTest annotation, try to use it without parameters at all. And make sure the test is put in a correct package, it matters. This will turn on the automatic resolution of your application.
Now I'll try to briefly explain why its important, the topic is really broad and deep.
Spring Boot checks whether the class annotated with #SpringBootConfiguration (its an annotation put on #SpringBootApplication - which is in turn is on your main class) exists in the same package as the integration test ( Lets say, com.abc.myapp.test is where you put a test)
If not found, it goes one package up and checks there (com.abc.myapp). It will do that again and again till the root package however, lets assume the #SpringBootApplication annotated class is in this package. Notice, If this recursive "search" doesn't find #SpringBootApplication annotated class - the test doesn't start. That's why its important to use the package structure offered by spring boot application.
Now when it finds that class it know which packages should be scanned for beans to start the spring boot application. So it tries to find beans according to practices of spring boot (package com.abc.myapp and beneath). It does it again recursively top-to-bottom this time.
It also runs your starters (autoconfigurations) in this mode.
So, bottom line:
Specifying #SpringBootTest without parameters makes spring boot doing its best to mimic the startup of the real application
If you use it with parameters where you put it a configuration however, it behaves totally differently: Its like saying: "I know where my configurations are, don't try to start everything, here is my configuration, load only it".
A totally different thing, no recursive searches, no auto-configurations startup, etc.

Using #Profile annotation for stubbing external behaviour

There are several web spring boot java applications. I need to prepare several components for integration testing. My task is to mock all external behaviour such as other projects's components, db calls etc. I found a solution for this using #Profileannotation from spring framework. Here's an example. I can simply create new profile and declare two beans implementations for each profile: one for real usage, for production and another one for integration testing, for stubbing. It would look like this:
#Profile("PROD")
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
#Profile("MOCK")
#Configuration
#EnableWebSecurity
public class SecurityMockConfig extends WebSecurityConfigurerAdapter {
}
But I have doubts about this design. It looks little bit messy for me. Does this solution considered acceptable for task I have?
Doing this, your mocks and their configuration will be probably packaged with the app running in production.
This seems very odd to me. Would you package your units tests in your deliverd Spring application ? I don't think so. So I would like to say this is a "bad" design since testing dependencies should not be embedded with production code.
However, Spring's documentation about #Profile annotation is using the exemple of environment segregation.
Now, there is a question which needs to be answered: what do you mean by "integration testing" ?
Is this automated integration test ? Or do you want to run your application in different modes for the testing teams ?
Is this is an automated integration test, then there is no reason to use #Profile annotation as automated tests and production code will not be packaged together.
However, if you want your users to make integration tests, then you could create standalone fake project which will be used to simulate the external dependencies you are calling (database, webservices, etc).
Then, #Profile can be used to switch from fake to production mode but only through configuration file: fake profile will make call on your fake external services whereas production will call the real external services.

Integration tests of Spring application

I am trying to implement integration tests for my Tomcat application, but my issue is that the application is launched separately from the tests so the tests cannot access the application context and neither the database.
My idea is running the tests "within" the running application, so I can #Autowire EntityManager and check for instance the state of the database during testing or even create database entities for testing.
My only idea of doing this is to actually run the application programmatically from the tests as ClassPathXmlApplicationContext("applicationContext.xml") and the access the Context. This would work, but it would be very hard for debugging as we wouldn't be able to use Hotswapping during the testing. Also I guess the server would be stopped as soon as the tests would end. I guess that is not the best and correct solution.
EDIT:
My question was probably unclear, so I will try to clarify.
I have a Tomcat application with Spring and Hibernate. The Spring beans and Hibernate database connection is initialised when the Tomcat application is started. The issue is how to run the tests of the active Spring beans from methods annotated with #Test in src/test/java which are started separately.
Consider this class:
#Component
class MyRepository {
#Autowired
EntityManager em;
#Transactional
public void myMethod(MyEntity entity) {
// do some job with entity
...
em.flush();
}
}
This class will be initialised with Tomcat as a MyRepository bean.
To test it, I cannot just call new MyRepository().myMethod(...) - I need to access the bean. The issue is accessing the bean from the #Test method:
#Test
void testMyRepository() {
Item item = ...
// then use the repository to handle the entity
context.getBean(MyRepository.class).myMethod(item);
// then assert the state of the database
context.getBean(EntityManager.class).find(Item.class, ...) ...
}
I can probably get the context in the initialisation of the tests with
ApplicationContext context = ClassPathXmlApplicationContext("applicationContext.xml");
But it would mean launching the whole application each time the tests are started. The better solution would be if the application could run separately from the tests.
Hope my problem is more clear now.
I would suggest you to use the SpringRunner to start the Spring application context and perform your tests on that running instance. You can customize the context the way it doesn't contain parts you don't want to tests and you can create mocks for components that require some external resources (REST clients and such). Take a look at the Spring docs or Spring Boot docs.
If multiple tests use the same Spring context configuration, the context is started just once and reused. So it's good to have it's configuration in a parent class of your tests. You can autowire any Spring bean into your test and test it.
You can use an in-memory database (such as H2) instead of a production one, so your tests are not dependent on an external infrastructure. To initialize the database, use tools like Flyway or Liquibase. To clear the database before each test, you can use the #Sql annotation.
You can find many examples of projects with such tests, for example my own demo.
If you want to test an external system, I would suggest something like JMeter.
Unfortunately you cant mirror your classes and use them in your tests. Thats a big disadvantage of web services. They always depend on user / machine interaction. With a lot of effort you can extract the functionality of the essential classes or methods and construct test scenarios etc. with jUnit.
The Overview of your possibilities:
special drivers and placeholders
you can use a logger with detailed log-level and file output. Then you created scenarios with the expected result and compare it with your log files.
Capture replay tools. They record your exection and replay them for monitoring.
I can also recommend using Selenium for the frontend tests.
Hope it helped.

Can I selectively disable Spring Data repositories for testing?

I'm writing a module-level integration test for a system using Spring Integration. I need the integration plan up and running but at this level am still using MockMvc and a mocked repository interface to ensure that I have all of my mappings, conversions, and message routing correct.
Right now, my module-level Enable configuration is meta-annotated with #EnableMongoRepositories, and the Spring test runner aborts because it doesn't have a live mongoTemplate to create the repositories from; the mock repository doesn't prevent the attempt to create real ones.
I know that I can conditionalize the inclusion of #EnableMongoRepositories, but is there simpler way to tell Spring Data not to create repository proxies if I'm already supplying mocks for them?
Basaically if I understand correctly you have two kinds of set up for your MongoDB repositories, mock and live. So you want to run integration tests and control the repository that is being used. I would suggest using "Spring Profiles".
create an simple interface say MongodbCofig
crate two configuration classes for mock and live. Make sure these classes implement MongodbConfig. Set the profiles (#Profiles) in both the classes.
Later activate the required profile before running the tests
For detailed understanding of profiles you can refer here

Categories