Struts2 pre-test ServletContext - java

I have two Struts2 Action classes - 'SetupAction' and 'MainAction'. 'SetupAction' sets up some file locations to read files. It implements the ServletContextListener:
#WebListener
public class SetupAction implements ServletContextListener {....}
I want to test methods in my 'MainAction' using JUnit4, in addition to using Cargo and Failsafe plugins to start a Tomcat7 instance before running tests and tearing it down afterwards.
The problem is I need 'SetupAction' to complete setup before running the tests. I want to run this as if it's on a real server which is why I'm avoiding mocks.
proxy.getAction() in 'MainAction' will return 'SetupAction' if I send a HTTP GET request to the server at the start of the test.
Any help/guidance would be greatly appreciated.

Related

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.

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.

Is it possible to test the properties injection correctness via JUNIT?

I have developed my application and I have a .properties file containing several key-value properties.
In my code I inject said properties like this:
#Value("${services.host}${services.name}")
private String hostname;
I am searching for a way to check every #Value inside of my code so to make sure that every property will be solved at runtime. Something like simulating my application startup.
Is it possible?
Yes, you can create a JUnit test class that loads your application context (just like your production code would) and then execute a test method that verifies that your property values have been injected.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {AppConfig.class})
public class SpringApplicationTest {
#Autowired
private MyServiceBean serviceBean;
#Test
public void shouldExecuteServiceBean_andProduceExpectedOutcome() {
//TODO test setup
serviceBean.doSomething()
//TODO assert output
}
}
In this example MyServiceBean.java is a class that would be executed from your Main class, so that you are testing the end-to-end logic of your application, including all of the spring dependency injections. Think of it as your "happy path" test scenario. I always include at least one test like this in my projects, to ensure that all of the spring injections are correct and load without error. You wan't to catch the errors before you build and deploy your code.
In the example above AppConfig.java is the same Spring configuration class you use when your code is deployed. You probably want to add another configuration class that overrides some properties/beans specifically for testing only.
#ContextConfiguration(classes = {AppConfig.class, TestConfig.class})
Using a test only class, you can mock out any dependencies that make testing difficult (i.e. use an in-memory database), and also override properties so you can test against "localhost" rather than another service which may or may not be available (so long as you can create an equivalent localhost service in your test setup).
Note: If you are finding it difficult to test your application due to too many dependencies, or external dependencies that cannot be swapped out easily, the pain you are feeling is a good guide to start thinking about how to change your architecture to support ease of testing. You also can just test portions of your application using the above concepts.

How to mock/stub Java container in unit testing?

I have an object that implements ServletContextListener which, according to the Java EE servlet spec, is invoked by the servlet container at deployment/startup time via its contextInitialized(ServletContext) method.
I am trying to write a unit test that simulates a servlet container starting up and deploying my ServletContextListener (so that I can determine if the app is initializing correctly).
Is this possible, and if so, how? Is it container-specific? If so I am using OGS. Looking for code that looks something like this:
#Test
public void shouldBootstrapAppAtDeployTime() {
// Given
GlassFishContainer container = new GlassFishContainer(); // ha!
MyApp app = mock(MyApp.class); // MyApp implements ServletContextListener
// When - deploy app to container
// Causes app.contextInitialized(ServletContext) to be called
container.deploy(app);
// Then - verify the method was called with any ServletContext
mock.verify(app.contextInitialized(Matchers.any());
}
This is sloppy pseudo-code with some poorly-implemented Mockito sprinkled in for demo purposes (just to get my intentions across). Thanks in advance!
Maybe you can solve this with Arquillian: http://arquillian.org/features/
From the web page:
Arquillian brings your test to the runtime, giving you access to container resources, meaningful feedback and insight about how the code really works.
I think your approach is slightly mistaken. What your unit test pseudocode does is testing the container logic that it correctly calls your ServletContextListener - I would trust the container doing that properly.
What I would do is testing your listener class directly, instantiate it, call the contextInitialized() method with a mock ServletContext (I see you're familiar with Mockito, an excellent tool for the job!), and do your assertions if your ServletContextListener did its job as expected.
Not sure if there is such testing framework. Even if it exists, it will not be testing in the real environment(which might be different from the testing environment).
The best way to write this kind of testcases is :
Deploy the war using ANT, the server you are using might be providing an MBean or something to deploy the application
Your listener might be doing some functionality when contextInitialized() method was invoked.
Write a client which makes a request to server and checks if the step 2 was successful or not.

Load testing for java client/server application

I have written a java client server application (not http), which i need to load test. However, most tools out there such as jmeter and grinder seem to be targeted to http requests. Any suggestions?
Thanks!
JMeter allows writing pluginns. If your application uses protocol other than HTTP it seems that the protocol is proprietary, so writing tests requires some custom implementation anyway. JMeter allows this and it is highly recommended.
since we have no idea what protocol you're using, write your own client in a way easily extendable for load testing.
You could have a look at Soatest which claims to be socket based and should be able to use whichever web protocol you are using (hopefully TCP/UDP).
You can use the JUnit4 or JUnit5 based load runners below which can simply accept your Unit tests and generate load on the target server. These need not be HTTP tests, these could be any tests annotated with #Test
JUnit4 based load runner
JUnit5 based load runner
The load configs look like below to ramp up or ramp down your load:
number.of.threads=2
ramp.up.period.in.seconds=10
loop.count=1
Your load test will look like below:
#LoadWith("our_load_config.properties")
#TestMapping(testClass = AnyTestEndPoint.class, testMethod = "anyTestMethod")
#RunWith(ZeroCodeLoadRunner.class)
public class LoadTest {
}
Your JUnit test which is fed to the load generator,
The test class looks like below:
import org.junit.Test;
public class AnyTestEndPoint {
#Test
public void anyTestMethod() throws Exception {
...
// You can have your client code invoking the target server
...
}
}
Note:
You can feed multiple Junit tests too to the load reactor, to generate load on different part of the server logic/apis/processes.
Visit the HelloWorld Examples for more details.

Categories