Setup method JUnit 5 TestSuite - java

I am trying to executes some tests using JUnit 5 Test Suite. Based on the documentation I found, I used #RunWith and #SelectPackages (from the dependency junit-platform-runner).
Before I started the tests defined in the #SelectPackages, I wanted to load some properties file in such a setup method. I tried using #BeforeAll, #ClassRule and #Rule, but those setup methods are only called in any test methods in the annotated class (RemoteTests). But the setup methods are not called before the executions of the test classes defined in the #SelectPackages (com.test.packages).
#RunWith(JUnitPlatform.class)
#SelectPackages("com.test.packages")
public class RemoteTests {
#Rule // I tried also #ClassRule and #BeforeAll here
public void setup() {
PropertiesLoader.loadProperties("remote.properties");
}
}
Are there any setup annotations for my purpose?

Related

Trouble executing a unit test that should ignore Spring annotations on the unit under test

I'm trying to execute a unit test for a service class that has an #Async("asyncExecutor") annotated method. This is a plain JUnit test class with no Spring runners and no intention of using Spring at all in the unit test. I get the exception,
BeanFactory must be set on AnnotationAsyncExecutionAspect to access qualified executor 'asyncExecutor'
Where asyncExectuor is the name of the bean to be used during normal execution. My configuration class looks like this and I solved that previous error message at runtime by adding the mode = AdviceMode.ASPECTJ portion. This service works at runtime without issue in an Async way.
#Configuration
#EnableAsync(mode = AdviceMode.ASPECTJ)
public class AsyncConfiguration {
#Bean(name = "asyncExecutor")
public Executor asyncExecutor() {
...
}
}
I don't understand why the Spring context is being constructed at all in the unit test. The test class is simply annotated #Test on the methods with no class annotations and no mention of Spring. I was hoping to unit test this service class method as a regular method ignoring the async nature, but the annotation is being processed for some reason.
I'm contributing to a much larger gradle + Spring 4 project that I'm not fully knowledgeable about. Is there anything I should be looking for to see if a Spring context is being created by default for all tests?
As you noticed, Spring context is not loaded, that is the reason of your error. Try to initialize Spring context in your test by adding #RunWith and #ContextConfiguration annotations

Spring boot cucumber TestExecutionListener before database initalization

I want to create integration test with docker before cucumber test start. Inspired by: http://tech.asimio.net/2016/08/04/Integration-Testing-using-Spring-Boot-Postgres-and-Docker.html
But in my case the TestExecutionListener is not started before database initialization. I use Flyway for database migrations and it seems it tries to initialize first. For this a database connection required, which is not available, due the TestExecutionListener not being executed.
These are my classes:
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {"json:target/integration-cucumber.json"},
features = "src/test/resources"
)
public class CucumberIntegration {
}
And my test class which I will be extended by the cucumber steps:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class)
#SpringBootConfiguration
#ContextConfiguration
#TestPropertySource(locations="classpath:application.properties")
#TestExecutionListeners({
DockerizedTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class
})
public class SpringIntegrationTest {
}
When I change #SpringBootTest(classes = Application.class) to #SpringBootTest I see DockerizedTestExecutionListener being executed. Only it fails because it misses configuration from Application.class.
Anyone idea how to this with or without TestExecutionListener?
This will not work because the Cucumber.class JUnit runner doesn't support TestExecutionListeners.
You might think that your test steps are executed by the SpringRunner.class JUnit runner, but they aren't.
The #RunWith(SpringRunner.class) annotation on your SpringIntegrationTest class is basically useless here, since according to your post, your subclasses of SpringIntegrationTest contain Cucumber steps. However the SpringRunner expects JUnit #Test methods. Cucumber steps with #Given, #When, #Then etc. are ignored because SpringRunner doesn't know what to do with them.
What really executes your test steps is the #RunWith(Cucumber.class) annotation in your CucumberIntegration class. The Cucumber runner, however, doesn't give a damn about the TestExecutionListeners annotation that your steps definition class inherits from SpringIntegrationTest because it doesn't support such a feature.
Execution listeners are a Spring-only feature. You won't be able to do what you want to do, at least not as long as you use Cucumber.

Spring dependencies not being injected into BeforeSuite method?

I am running a spring boot application that uses TestNG as the testing framework. My tests are set up like this:
A parent class, which is in charge of setup logic and takes care of all of the configuration stuffs:
#ContextConfiguration(classes = {TestingConfig.class}, initializers = ConfigFileApplicationContextInitializer.class)
#ContextConfiguration(classes = TestConfig.class)
#TestPropertySource(locations = "classpath:application.yml")
public abstract ParentTestClass extends AbstractTestNGSpringContextTests {
#Autowired
private ServiceClient serviceClient;
#BeforeSuite
public void beforeClass() {
Assert.assertNotNull(serviceClient);
serviceClient.doSomeSetupWork();
}
}
There are multiple child test classes. Each on inherits form the parent test class so that they share the same setup logic.
public ChildTestClass1 extends ParentTestClass {
#Test
public void someTest() {
...
}
// More tests not shown
}
public ChildTestClass2 extends ParentTestClass {
#Test
public void anotherTest() {
...
}
// More tests not shown
}
The serviceClient is a client for one of the web services that the test suite depends on. I am making calls with the service client to set up the data in the other service before running the test cases.
The problem is this: previously I was using the #BeforeClass annotation, which meant that the parent class's setup method was being run once for every child test class. This was ok, but it was really slow waiting for the same setup to be run multiple times.
So I thought to myself: I'll just change the #BeforeClass annotations in the ParentTestClass to be #BeforeSuite instead! That will solve all of my problems!
Wrong.
Now when I run it, the Assert.assertNotNull(serviceClient); line in the beforeClass() method of the parent class fails. In short, Spring dependencies aren't being injected into the #BeforeSuite annotated method, even tho they were being injected in the method when it was annotated with #BeforeClass.
Any thoughts here? I'd really appreciate it!
I believe this is working as designed. From looking at how the implementation is built within org.springframework.test.context.testng.AbstractTestNGSpringContextTests (from which you extend), the dependencies are injected into your test class via the org.springframework.test.context.support.DependencyInjectionTestExecutionListener#injectDependencies (this is a listener).
All the listeners including the DependencyInjectionTestExecutionListener is invoked only via org.springframework.test.context.testng.AbstractTestNGSpringContextTests#springTestContextPrepareTestInstance which is a #BeforeClass(alwaysRun=true) classified method.
So your dependencies aren't available to you until and unless this #BeforeClass annotated method runs to completion. So you would have to move out your #BeforeSuite method and have it work with a #BeforeClass annotation only.
If you don't need your service setup to be done multiple times, then you would need to add an edit check in your test code that does the setup ONLY IF ITS NOT DONE.
Here is the solution to all your problem.
#Override
#BeforeSuite
protected void springTestContextPrepareTestInstance() throws Exception {
super.springTestContextPrepareTestInstance();
}
Hope this helps you to inject the dependencies.

Junit method invocation fails due to spring injection

I have written Junit test class to test particular method. One of the variables being processed in this method is spring injected, by taking the value from properties file.
Below is my test method
#Test
public void myTestMethod() {
//invoking the method to be tested
Assert.assertTrue(updateGroceries());
}
This is the class to be tested,
public class ToBeTested {
//Spring injected value
String categories;
public boolean updateGroceries() {
List<String> categoryList = StringUtils.convertStringToList(categories);
}
In the above class, categories variable is spring injected.
This is properties file content:
categories = Dals,Pulses,Dry Fruits,Edible Oil
Now while running my Junit method, execution is failing because dependency injection is failing.Since the code I want to test runs on tomcat. I want to test the code without running tomcat. Please suggest some solution.
First of all to run mockito you need to enable it over your test.
Using annotation #RunWith(MockitoJunitRunner.class) or execute at the beginning of your test Mockito.initMocks().
Then your test should look like:
#RunWith(MockitoJunitRunner.class)
private YourTest{
#InjectMocks
ToBeTested toBeTested;
#Mock
ToBeTestedDependency dependency;
#Before
public void setUp(){
ReflectionTestUtils.setField(toBeTested, "categories",
"someCategory");
}
#Test
public void shouldDoThisOrThat(){
toBeTested.updateCategories();
}
}
Unfortunately mockito doesn't support injecting #Valueannotated field. You need to use ReflectionTestUtils or setup run your test with SpringJUnit4ClassRunner where you need to define your spring context with PropertyPlaceholder configuration to resolve property that you have as your Value key. There you can find reference to documentation and example of spring testing approach.
Hope this helped.
You should look at Mockito. When you use mockito framework, you can create mocks for spring injected values. You should read more on mockito website.

how to unit test method dependent on springBoot applicationContext?

I am trying to write a unit test for a static method which takes a class and method name and does some reflection to call the method with arguments and store the results. I'm using spring-boot.
My test actually works when I run the full suite, but when I run the test as standalone it fails. The problem is that I've created a mock class (a hand written mock, not using mockito or easymock) which I want the static method to use. However, the reflection can not detect my mock class because the class has not been loaded into the applicationContext by spring-boot. Here is the line that fails:
T proxy = SpringApplicationContext.getBean(clazz);
SpringApplicationContext definition:
#Component
public class SpringApplicationContext implements ApplicationContextAware
{
private static ApplicationContext applicationContext_;
#Override
public void setApplicationContext(ApplicationContext applicaitonContext) throws BeansException {
applicationContext_=applicaitonContext;
}
public static <T> T getBean(Class<T> requiredType) throws beanException {
return applicationContext_.getBean(requiredType);
}
*note, I had to retype by hand, please assume obvious syntax errors are typos.
so basically my applicationContext is not being set or defined. I only need one mock bean in the applicationContext, I could do it by hand, but is there a more spring approach using annotations?
It turns out that my test didn't work rather the were run stand alone or part of a suite, I had a separate issue with using the wrong annotations for #BeforeTest which masked the defect when running the whole suite.
The fix was pretty simple. I added the SpringApplicationConfiguration annotation above my test:
#SpringApplicationConfiguration(classes =
{
MockController.class,
SpringApplicationContext.class
}
public class MyTest extends AstractTestNGSpringContextTests
There are two parts to this. The #SpringApplicationCOnfiguration loads only those values I listed. I could have pointed to configuration classes, but that would ultimately load most of the beans in my enviroment which is overkill for a unit test. So I load the two #component objects needed in my ApplicationContext for my unit test to work only.
I also had to extend AbstractTestNGSpringContextTests because It's the only way to get spring to play nice with the TestNG kit were using for our tests. If others are using junit tests instead of TestNG don't extend the AbstracTestNGSpringContextTests, instead I believe your want to add the annotation:
#RunWith(SpringJUnit4ClassRunner.class)
Though I haven't used it since I'm not using junit.
Hopefully this answer saves others who are trying to figure out how to load only a few classes instead of the entire enviroment (most examples I found want you to load configuration files that will load every bean, which is slow and honestly undesirable in a unit test).
Arguably I should still have mocked out the SpringApplicationContext entirely, I'm lazy and sloppy :)

Categories

Resources