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.
Related
I'm using IntelliJ IDEA CE 2018.3 and JUnit 4.12.
I have a test class that looks like this:
#RunWith(HierarchicalContextRunner.class)
public class TestClass {
#BeforeClass
public static void beforeAll() {
//start a server for all tests to hit
}
#Before
public void before() {
//init a common request object for each test
}
#Test
public void itShouldHaveSomeCommonProperty() {
//check some common thing
}
public class SomeSubTestClass {
#Before
public void before() {
//do some test case-specific setup
}
public class SomeOtherSubTestClass {
#Test
public void itShouldDoSomething() {
//hit the service and assert something about the result
}
}
}
}
When I tell IntelliJ to run the class, everything works as expected. However, if I want to just run the itShouldDoSomething test (which I'm doing by setting up a run configuration that targets the SomeOtherSubTestClass class), the beforeAll method is not executed. Both of the before methods are executed in the correct order, but not the static beforeAll method.
Am I misunderstanding something, or is this a bug?
It is not a bug.
The beforeAll method is static and therefore tied to the class and not the instance. This is why it is not executed when calling tests in inner classes or sub-classes.
To ensure it being called you would have to define a #BeforeClass method in each of your inner classes which then call the method on the outer class.
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.
We use a custom Guice scope, #TestScoped, for some of our JUnit tests that lasts for a single test method, and a JUnit #Rule to enter and exit the scope appropriately. It looks like this:
public class MyJUnitTest {
#Rule public CustomRule customRule = new CustomRule(MyModule.class);
#Inject private Thing thing;
#Test
public void test1() {
// Use "thing"
}
#Test
public void test2() {
// Assuming "Thing" is #TestScoped, we'll have a new instance
}
}
We're starting to use TestNG for some of our tests in other projects, and we'd like to have a similar pattern. So far we've come up with this:
#Listeners(CustomTestNGListener.class)
#Guice(modules = MyModule.class)
public class MyTestNGTest {
#Inject private Provider<Thing> thingProvider;
#Test
public void test1() {
Thing thing = thingProvider.get();
// Use "thing"
}
#Test
public void test2() {
Thing thing = thingProvider.get();
// Assuming "Thing" is #TestScoped, we'll have a new instance
}
}
public class CustomTestNGListener implements IHookable {
#Override
public void run(IHookCallBack callBack, ITestResult testResult) {
TestScope.INSTANCE.enter();
try {
callBack.runTestMethod(testResult);
} finally {
TestScope.INSTANCE.exit();
}
}
}
There are a couple issues with this design:
Unlike JUnit, TestNG uses the same instance of the test class for each method. That means we have to inject Provider<Thing> instead of just Thing, which is awkward.
For some reason, CustomTestNGListener is running on all of our tests, even ones that don't have that #Listeners(CustomTestNGListener.class) annotation. I've worked around this by explicitly checking for that annotation in the listener itself, but it feels like a hack (though I do see that MockitoTestNGListener does the same thing).
Does someone with more familiarity with TestNG have any suggestions for dealing with these issues?
Instead of
public class MyTestNGTest {
#Inject private Provider<Thing> thingProvider;
#Test
public void test1() {
Thing thing = thingProvider.get();
In TestNG you can used
public class MyTestNGTest {
#Inject
private Thing thingInjected;
private Thing thing;
#BeforeTest
public void doBeforeTest() {
thing = thingInjected.clone();
}
Or just call thingProvider.get() in doBeforeTest(), it's better in you have a lot of # Test
public class MyTestNGTest {
#Inject private Provider<Thing> thingProvider;
private Thing thing;
#BeforeTest
public void doBeforeTest() {
thing = thingProvider.get();
}
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);
}
}
I have two test classes, MyFirstTest and MySecondTest. Running each independently works fine. When I run both (in eclipse select the test folder which contains these files, right click, run as junit), MySecondTest fails because MyClass is still mocked when it runs its' tests. MyFirstTest requires MyClass to be mocked. MySecondTest requires MyClass to not be mocked. I thought the tearDownMocks was suppose to 'demock' the classes.
public class MyFirstTest {
#Before
public void setUp() throws Exception {
Mockit.setUpMocks(MockMyClass.class);
}
#After
public void tearDown() throws Exception {
Mockit.tearDownMocks(MockMyClass.class);
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
Mockit.tearDownMocks(MockMyClass.class);
}
#MockClass(realClass = MyClass.class, stubs = "<clinit>")
public static class MockMyClass {
...
public class MySecondTest {
The right way to do it is like mentioned below: Mock the class and assign it to a variable. And then, using that variable, you can destroy or clear the mock so that it doesn't impact any other test case.
MockUp<PmRequestData> mockpmreq = new MockUp<PmRequestData>() {
#Mock
public Map<String, KPIData> getKpiDataMap() {
return datamap;
}
};
mockpmreq.tearDown();
The Mockit.tearDownMocks() method accepts real classes and not the mocks. So, the right code would be:
Mockit.tearDownMocks(MyClass.class);