I want to use beans in tear-down method in spring unit test (SpringJUnit4ClassRunner).
But this method (that is annotated with #AfterClass) should be static. What can be the solution?
example:
#RunWith(SpringJUnit4ClassRunner.class)
//.. bla bla other annotations
public class Test{
#Autowired
private SomeClass some;
#AfterClass
public void tearDown(){
//i want to use "some" bean here,
//but #AfterClass requires that the function will be static
some.doSomething();
}
#Test
public void test(){
//test something
}
}
Perhaps you want to use #After instead of #AfterClass. It isn't static.
JUnit uses a new instance for each test method, so in #AfterClass execution the Test instance don't exists and you can't access to any member.
If you really need it, you could add a static member to the test class with the application context and set it manually using an TestExecutionListener
for example:
public class ExposeContextTestExecutionListener extends AbstractTestExecutionListener {
#Override
public void afterTestClass(TestContext testContext) throws Exception {
Field field = testContext.getTestClass().getDeclaredField("applicationContext");
ReflectionUtils.makeAccessible(field);
field.set(null, testContext.getApplicationContext());
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners(listeners={ExposeContextTestExecutionListener.class})
#ContextConfiguration(locations="classpath:applicationContext.xml")
public class ExposeApplicationContextTest {
private static ApplicationContext applicationContext;
#AfterClass
public static void tearDown() {
Assert.assertNotNull(applicationContext);
}
}
Related
Trying to register beans dynamically via SpringApplicationBuilder class and it's working when running the app, but when trying to execute the test and trying to verify that the beans are defined in the context, they fail for the dynamic bean. Feel like I have to use another "magical" annotation for the tests for them to properly load the dynamic beans.
This is the code used and if you run the tests you will see that both cases will fail. BarService will fail also because FooService is registered dynamically via builder, but if you would remove the dependency it will pass the BarService test.
SpringApp.java
class FooService {
}
#Component
class BarService {
private final FooService fooService;
BarService(FooService fooService) {
this.fooService = fooService;
}
}
#SpringBootApplication
public class SpringApp {
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(SpringApp.class)
.initializers((ApplicationContextInitializer<GenericApplicationContext>) context -> {
context.registerBean(FooService.class);
})
.run(args);
}
}
SpringAppTest.java
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = SpringApp.class)
public class SpringAppTest {
#Autowired
ApplicationContext context;
#Test
public void barService() {
Assert.assertNotNull("The barService should not be null", context.getBean(BarService.class));
}
#Test
public void contextLoads() {
Assert.assertNotNull("The fooService should not be null", context.getBean(FooService.class));
}
}
First solution
The main error here is that the test does not have the initalization logic that the main method has. Solution is to extract the logic from the initializers method
class MyInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
#Override
public void initialize(GenericApplicationContext context) {
System.out.println("Called initialize");
context.registerBean(FooService.class);
}
}
and use it in main
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(SpringApp.class)
.initializers(new MyInitializer())
.run(args);
}
and then use the MyInitializer in the test file through #ConextConfiguration
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = SpringApp.class, initializers = MyInitializer.class)
public class SpringAppTest {
// ...
}
Second (better) solution
Now, this can be cumbersome as we need to reference this initializer in every test, but there is an even better solution. We can create a specific Spring file resources/META-INF/spring.factories and put inside of it a reference to the initializer:
org.springframework.context.ApplicationContextInitializer=com.acme.orders.MyInitializer
After that, we can simplify both the main method
#SpringBootApplication
public class SpringApp {
public static void main(String[] args) {
SpringApplication.run(SpringApp.class, args);
}
}
and the tests, so that they don't need to always import the initializer.
#RunWith(SpringRunner.class)
#SpringBootTest
public class SpringAppTest {
// ...
}
Now both the main run process and the tests will have access to all the beans.
I have multiple testNG test classes that extend a Base Test class and all use the same common objects. I want to have the object creation done automatically in BaseTest so I don't have to include it in each test class. As of now, the code only works if I add createPages() to the start of the test. I tried putting them in the BaseTest class using #BeforeClass and #BeforeSuite but both gave a null pointer exception meaning they weren't instantiated before the #Test test123 was run I beleive.
public someTest extends BaseTest {
#Test
public void test123(){
createPages(); //i want to be able to remove this and have it done in BaseTest
menuPage.scroll();
}
}
public BaseTest {
MenuPage menuPage;
public void createPages() {
menuPage = new MenuPage(getDriver());
}
/*
#BeforeSuite
public void beforeSuite() {
createPages();
}
#BeforeClass
public void beforeClass() {
createPages();
}
*/
}
#beforeTest is one such annotation. A method with #beforeTest annotation will run, before any test method belonging to the classes inside the test tag
inside ur BaseTest
public class Basetest{
#BeforeTest
public void doBeforeTest() {
createPages();
}
}
It turns out that JUnit wants #BeforeClass and #AfterClass to be static and this doesn't get along well with JerseyTest's configure method override. Is there a known way to configure the Jersey application while still being able to access JUnit's utility methods?
public class MyControllerTest extends JerseyTest {
#BeforeClass
public static void setup() throws Exception {
target("myRoute").request().post(Entity.json("{}"));
}
#Override
protected Application configure() {
return new AppConfiguration();
}
}
Hence beforeClass needs to be static, target cannot be called because of its instance-method nature. While trying to use the constructor instead, it turns out that configure is run after the constructor and this prevents the setup-request to be executed and will therefor fail naturally.
Any advice is more than appreciated, thanks!
What we did in several cases to avoid heavy setups in such situations is to use a boolean flag to run that setup conditionally.
public class MyControllerTest extends JerseyTest {
private static myRouteSetupDone = false;
#Before
public void setup() throws Exception {
if (!myRouteSetupDone) {
target("myRoute").request().post(Entity.json("{}"));
myRouteSetupDone = true;
}
}
#Override
protected Application configure() {
return new AppConfiguration();
}
}
#Before does not require the static modifier and will be executed before every test-method.
Currently for tests I'm using TestExecutionListener and it works just perfect
public class ExecutionManager extends AbstractTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
System.out.println("beforeClass");
}
#Override
public void afterTestClass(TestContext testContext) throws Exception {
System.out.println("afterClass");
}
}
Test classes:
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners(ExecutionManager.class)
public final class TC_001 {
#Test
public void test() {
System.out.println("Test_001");
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners(ExecutionManager.class)
public final class TC_002 {
#Test
public void test() {
System.out.println("Test_002");
}
}
When I include those tests in test suite, beforeTestClass(TestContext testContext) and afterTestClass(TestContext testContext) methods are executed for each test class, what is quite logical:
#RunWith(Suite.class)
#Suite.SuiteClasses({
TC_001.class,
TC_002.class
})
public final class TS_001 {
}
Is there anything like SuiteExecutionListener (TestExecutionListener for suites)?
Basically I need non-static #BeforeClass and #AfterClass for suite
OR
In ExecutionListener I need to find out what class has been launched: case or suite. For this purpose I can:
analyze StackTrace and get calling class
use Reflection.getCallerClass(int i) (which is deprecated)
pass caller class to ExecutionManager (By the way, how can I do that? Is it possible to put Object into TestContext like in Android Bundle?)
But I don't really like those solutions. SuiteExecutionListener is much more preferable
Thank you
No, there is unfortunately no such thing as a SuiteExecutionListener in the Spring TestContext Framework (TCF).
The TCF does not integrate with JUnit 4 at the suite level.
If you want to store something in the TestContext, that's not a problem. TestContext implements org.springframework.core.AttributeAccessor, so you can store attributes in the TestContext. Note, however, that the lifecycle of a given TestContext is tied to a test class.
I am trying to execute a code (in which I am auto wring a property) before executing any junit test using Before Class annotation but here problem is that annotated method called before application context load due to this I get the null value in property (helloWorld).
Please refer code for the same
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:/SpringBeans.xml")
public class JunitTest {
#Autowired
private static HelloWorld helloWorld;
#BeforeClass
public static void methodBefore(){
helloWorld.printHello();
System.out.println("Before Class");
}
#Test
public void method1(){
System.out.println("In method 1");
}
#Test
public void method2(){
System.out.println("In method 2");
}
#Test
public void method3(){
System.out.println("In method 3");
}
#Test
public void method4(){
System.out.println("In method 4");
}
#AfterClass
public static void methodAfter(){
System.out.println("After Class");
}
}
In the same way I want to execute some code after executing all junit test.
please suggest how can I achieve above things
you shouldn't use static on autowired field. see more here: Can you use #Autowired with static fields?
remove the static from HelloWorld and you should be ok
You cannot autowire the static field - just remove the static modifier from helloWorld field.
Now the problem is that #BeforeClass annotation can be put on static methods only. You'll have to replace this method with Spring TestExecutionListener.beforeTestClass(TestContext) method
Depending on your requirements you might take on of the existing listeners like TransactionalTestExecutionListener which can call your methods say before the transaction is started, e.t.c.