Hierarchy of JUnit tests - junit

I need the following test
#runwith(cache, memory)
class CollectionA is -- this is a suite (aka folder)
class Cache { -- this is a sub-suite (aka folder)
#test testCache1() -- this is a method (aka file)
#test testCache2()
#test testCache3()
}
class RAM { -- this is a sub-suite (aka folder)
#test testRAM1()
#test testRAM2()
}
#test testIO()
#test testKeyboard()
#test testMouse()
#test testMonitor()
#test testPower()
#test testBoot()
Please note that only Cache and RAM need to be grouped. The hierarchy helps to fight the complexity and run related tests, e.g. Cache subsystem, alone, when necessary. The problem that is as soon I use #runwith to do that grouping, all the single test methods besides the RAM and Cache collections are ignored by JUnit. It seems that you cannot have sibling files and folders in JUnit design. The comments in the official example of grouping also hints that
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestA.class,
TestA.class
})
public class FeatureTestSuite {
// the class remains empty,
// used only as a holder for the above annotations
// HEY!!! WHAT ABOUT MY #Tests HERE?
}
The answers say that whether I need to wrap every single test, e.g. testPower into their singletone suit or flatten the suite - get rid if the hierarchy completely.
So, is it right that JUnit is designed to disallow mixing single files (#test methods) with the folders (#runwith suites)? Why? How can this be worked around? Might be there is an alternative to #runwith.Suite?

What you like to create is a mixin type, which is not supported by the JUnit runner. So yes, you are right, it is not possible out of the box.
For this purpose I created an add-on that can be used to create hierarchical contexts for your test. In my point of view this is a missing feature in JUnit and I also stay in contact to get this included into the JUnit core.
The add-on provides an HierarchicalContextRunner which allows to use inner class to group your tests into contexts. Each context can contain tests or other contexts. It also allows to have #Before, #After, #Rule methods and fields, as well as other feature like #Ignore of the standard Runner. :-)
Example:
#RunWith(HierarchicalContextRunner.class)
public class CollectionA {
public class Cache {
#Test testCache1() {...}
#Test testCache2() {...}
#Test testCache3() {...}
}
public class RAM {
#Test testRAM1() {...}
#Test testRAM2() {...}
}
#Test testIO() {...}
#Test testKeyboard() {...}
#Test Mouse() {...}
#Test testMonitor() {...}
#Test testPower() {...}
#Test testBoot() {...}
}
Give it a try:
https://github.com/bechte/junit-hierarchicalcontextrunner/wiki
Votes and feedback are highly appreciated. :)

Your design should be something like this:
// folder com.myco.project
SuiteX.java
TestA.java
TestB.java
// contents of TestA.java
public class TestA{
#Test
public void someTestInA(){...}
}
// contents of TestB.java
public class TestB{
#Test
public void someTestInB(){...}
}
// contents of SuiteX.java
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestA.class,
TestB.class
})
public class FeatureTestSuite {
// the class remains empty,
// used only as a holder for the above annotations
}
As I state in my comment, use separate java files for each test class. Do not use inner classes.

Related

Testing class which creates objects from other classes

I have a class Component which creates two objects from other classes JMSConnector and AppiaConnector and links both of them.
I have a method that reads the status of both objects and return a combined value.
Here is the code:
Problem I am facing when testing this method is I have no way of injecting mocks of appiaConnector and jmsConnector to test the behaviour of this method.
For example I tried this:
#RunWith(MockitoJUnitRunner.class)
public class ComponentTest {
#Mock
JMSConnector jmsConnector;
#Mock
AppiaConnector appiaConnector;
Component component = new Component();
#Test
public void testGetStatus() {
given(jmsConnector.getStatus()).willReturn(true);
given(appiaConnector.getStatus()).willReturn(true);
// this is what I want... but I can't dynamically inject these mocks into component ???
assertTrue(component.getStatus());
}
}
Is there a way that I can achieve this, or should I use stubs? (which seems an overkill for such a small method)
You can pass them as parameters instead of creating them inside the method.
public Component(AppiaConnector appiaConnector, JMSConnector jmsConnector) {
// do your status check
}
Now if in your production code, you don't want to inject them, you can always create another constructor with no parameters. That way you keep your code the same but gain in testing flexibility
public Component() {
this(new AppiaConnector(), new JMSConnector());
}
Component(AppiaConnector appiaConnector, JMSConnector jmsConnector) {
// do your status check
}

How can I configure JUnit to ignore #Before and #After annotations

We have many test classes that are annotated with #Before and #After to perform test construction/destruction.
But because we now need to perform actions on test failure but prior to #After executing we have used a RuleChain to handle test construction / destruction ourselves. It just points back to the setUp() and tearDown() methods (yes we were lucky that most developers had stuck to that convention).
The problem is that JUnit still invokes the methods annotated with #Before and #After as well as invoking them via the new Rule.
At it's core JUnit is invoking
org.junit.internal.runners.statements.RunAfters.evaluate
for the innermost statement.
One option is obviously removing the #Before and #After annotations from the Tests, but we are talking about many hundreds of tests.
How can we switch off processing of #Before and #After ?
I don't think you can flick a JUnit 'switch' to disable this behaviour. JUnit offers two ways of changing test execution behaviour:
Extend BlockJUnit4ClassRunner
Add a Rule to your test case
Both of these require you to change your test cases, of these the second option might be least invasive (though that does depend on whether your test cases are already using customised runners).
Given this simple JUnit runner:
public class IgnoreBeforeAndAfter extends BlockJUnit4ClassRunner {
public IgnoreBeforeAndAfter(Class<?> klass) throws InitializationError {
super(klass);
}
protected Statement withBefores(FrameworkMethod method, Object target,
Statement statement) {
return statement;
}
protected Statement withAfters(FrameworkMethod method, Object target,
Statement statement) {
return statement;
}
}
The following test case will pass (thereby proving that the #Before and #After methods are not invoked):
#RunWith(IgnoreBeforeAndAfter.class)
public class SimpleTest {
#Before
public void setUp() {
Assert.fail("The #Before method should be ignored!");
}
#After
public void tearDown() {
Assert.fail("The #After method should be ignored!");
}
#Test
public void canIgnoreBeforeAndAfter() {
assertTrue(true);
}
}
A structural search+replace on your code base could be used to add this annotation to all test cases which contain at least one of #Before or #After.
Though of course a structural search+replace could also remove all #Before and #After annotations from your code.
An approach which requires no changes to your existing test cases (but which is somewhat non standard) would be to provide no-op implementations of ...
org.junit.internal.runners.statements.RunAfters
org.junit.internal.runners.statements.RunBefores
... in your own code base, these would 'replace' the JUnit equivalents and if their evaluate() method body was empty then your use of the #Before and #After annotations would have no effect.

Ignoring invoking internal static call

public static ResponseBean call(Bean bean) throws Exception {
// statements...
IgnoreCall.ignoreMethodCall(bean);
// statements...
// return
}
With the code snippet above, is it possible to test the method ignoring invocation of IgnoreCall.ignoreMethod(Bean) without needing to place the entire statement under a boolean condition?
Here's the unit test code snippet:
#RunWith(PowerMockRunner.class)
#PrepareTest
public ClassHelperTest {
#Test
public void testCall() throws Excpetion {
// stubbing...
ResponseBean responseBean = ClassHelper.call(bean);
// verify/ies
// assert/s
}
}
Notes:
Refactoring ClassHelper.call(Bean) should be avoided. Even with a bad OO design, refactoring is costly.
Method signature is locked unless another pattern is applicable for replacement.
Tried using Mockito.when and PowerMockito.when on the target static method, stubbing didn't work on run-time debug.
As your comments indicate that changing your production code is not possible, you "simply" have to dive into the static-mocking aspects of PowerMock; as outlined here for example.
Basically you need to enable IgnoreCall for static mocking; and then you make calls to ignoreMethodCall() a no-op.
But as you keep asking: the core problem with your question is the fact that you want to mock out a static method that is void. I have a complete example below, but before that some explanations.
The point is: you call a method for two reasons:
It has a side effect
It returns a value, and maybe, causes a side effect, too
A void method can only be called for side effects. And the thing is: when you do static mocking, then that works on class level.
Meaning: you instruct PowerMock to "prevent" any of the static methods of some class from execution; you simply "erase" the side effects of all those static methods! So, by telling PowerMock to do those static mocks, all void methods are already "gone".
But as said, you might also call methods for their return value. And then is when the when() method of Mockito kicks in. You use that method to say: when that value-returning method is invoked, then do this or that.
Long story short; here is a [mcve] using the elements you asked for:
package ghostcat.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
class IgnoreCall {
public static void ignoreMethodCall(Object o) {
System.out.println("SHOULD NOT SHOW UP: " + o);
}
}
class CuT {
public static Object call(Object bean) {
System.out.println("statement1");
IgnoreCall.ignoreMethodCall(bean);
System.out.println("statement2");
return "whatever";
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(IgnoreCall.class)
public class PMTest {
#Test
public void test() {
PowerMockito.mockStatic(IgnoreCall.class);
CuT.call("yeha");
}
}
As in your example ... there is IgnoreCall; used within that a static method that I just called "call".
This prints:
statement1
statement2
When I go in and comment out
// PowerMockito.mockStatic(IgnoreCall.class);
It prints:
statement1
SHOULD NOT SHOW UP: yeha
statement2
So, a simple example that should tell you exactly what you need to do.
I worked with eclipse neon, IBM java8 JDK, and simply imported all the JARs from powermock-mockito-junit-1.6.6.zip into my test project.

Is it possible to name a test suite in JUnit 4?

In JUnit3, one would could name a test suite like this:
public static Test suite() {
TestSuite suite = new TestSuite("Some test collection");
suite.addTestSuite(TestX.class);
return suite;
}
Is there an equivalent way to do this in JUnit4?
Thanks.
EDIT
Thank you, I actually managed to get it working. My question was if there is a JUnit4 equivalent way of specifying the name/description of a test suite, like in JUnit3 with "Some test collection".
Some background:
I'm converting junit tests in legacy code to the version 4, and I don't want to lose any information if possible. I apologize, I should really have been more specific in the original question.
You can do this with the Suite runner #RunWith(Suite.class):
#RunWith(Suite.class)
#SuiteClasses({Test1.class, Test2.class, TestX.class})
public class MySuite {}
Where Test1, Test2, TestX contain your tests
ref. RunWith, Suite
update:
WRT changing the actual description of your suite, I don't think there's a way to do it out-of-the-box (if there is I haven't seen it yet). What you can do, is to define your own runner with a custom description [update2]:
#RunWith(DescribedSuiteRunner.class)
#SuiteClasses({Test1.class, Test2.class, TestX.class})
#SuiteDescription("Some test collection")
public class MySuite {}
public class DescribedSuiteRunner extends Suite {
// forward to Suite
public DescribedSuiteRunner(Class<?> klass, RunnerBuilder builder)
throws InitializationError {
super(klass, builder);
}
#Override
protected String getName() {
return getTestClass()
.getJavaClass()
.getAnnotation(SuiteDescription.class)
.value();
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface SuiteDescription {
String value();
}
The default implementation of getName just returns the class being tested's name
Yes, In JUnit 3.x, the JUnit methods had to be specifically named. They needed to begin with the word test in order for JUnit to run that as a test case. Now you can just use the #Test annotation:
#Test
public void thisIsMyTest() {
// test goes here
}
Also in JUnit4 you can state if you want some tests to run before or after all the tests in this class are invoked:
#Before
public void init() throws Exception {
System.out.println("Initializing...");
}
#After
public void finish() throws Exception {
System.out.println("Finishing...");
}
Further comparisons between JUnit3 and JUnit4 here and here.
Edit: after blgt's comment, I see I might have misunderstood your intent.
You are probably looking for #RunWith(Suite.class) - When a class is annotated with #RunWith, JUnit will invoke the class in which is annotated so as to run the tests, instead of using the runner built into JUnit. Full example of usage is here, tl;dr below:
#RunWith(Suite.class)
#SuiteClasses({ FirstTest.class, SecondTest.class })
public class AllTests {
...
}

How to two runner property include in one test case class?

#RunWith(DataProviderRunner.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class DatabaseModelTest {
// some tests
}
or
#RunWith(Parameterized.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class DatabaseModelTest {
// some tests
}
We can not use two runner property in one test case class...!! so that
I want to run test case with Multiple data how i pass multiple parameter in Rest web service to execute test case ??
Any solution for extend class for DataProviderRunner or parameterized ??
Thanks
(stayconnected52)
You could use Spring's JUnit rules instead of the SpringJUnit4ClassRunner. This works at least with the Parameterized runner. I don't know whether it works with the DataProviderRunner, too.
You need at least version 4.2.0 of the Spring framework and spring-test.
#RunWith(Parameterized.class)
public class DatabaseModelTest {
#ClassRule
public static final SpringClassRule SCR = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
...
}
I tested the solution of #Stefan and works also well for #RunWith(DataProviderRunner.class)
I found a second solution in DataProvider for Spring Integration Testing, they wrote a class DataProviderRunnerWithSpring and set the test class like:
#RunWith(DataProviderRunnerWithSpring.class)
public class TestClass{
...
}