How to reuse existing JUnit tests in another test class? - java

how can I reuse JUnit tests in another testclass?
For example:
public TestClass1 {
#Test
public void testSomething(){...}
}
public TestClass2 {
#Test
public void testSomethingAndSomethingElse() {
// Somehow execute testSomething()
// and then test something else
}
}

Avoid the scenario, in general. It is prone to making tests much more brittle. If TestClass1 fails, then TestClass2 implicitly fails, which isn't desirable for at least the following reasons:
Code is tested more than once, which wastes execution time.
Tests should not rely on each other, they should be as decoupled as possible
If this becomes a pattern, it will become harder to identify what section of code is broken by looking at which tests are failing, which is part of the point of tests
Occasionally sharing sections of test code is useful, particularly for integration tests. Here's how you might do it without depending on the tests themselves:
public abstract BaseTests {
protected void somethingHelper() {
// Test something
}
}
public TestClass1 extends BaseTests {
#Test
public void testSomething(){
somethingHelper();
}
}
public TestClass2 extends BaseTests {
#Test
public void testSomethingAndSomethingElse() {
somethingHelper();
// and then test something else
}
}
Alternatively, you could use a helper class and avoid the inheritance altogether. Asserts and the like can go in the somethingHelper() method.
Don't call a method from TestClass1 in TestClass2 directly. The test cases become less readable this way, and can lead to spaghetti frittata.

As usual you can:
Extends TestClass2 from TestClass1
Access TestClass1 from TestClass2 using delegation:
Example 1:
// Instantiate TestClass1 inside test method
public TestClass2 {
public void testSomethingAndSomethingElse1() {
new TestClass1().testSomething();
}
}
Example 2:
// Instantiate TestClass1 as a member of TestClass2
public TestClass2 {
private TestClass1 one = new TestClass1();
public void testSomethingAndSomethingElse1() {
one.testSomething();
}
}

This is common to run a test with a different configuration. Do not worry about and go ahead.
At the first step create your own test without considering any configuration:
public abstract BaseTests {
#Test
protected void somethingHelper() {
// Test something
}
}
Then, extend the test class and add some configuration:
public TestClass1 extends BaseTests {
#Before
public void setup(){
// TODO: config
}
}
It is not necessary to do specific configuration but it is very common with a configurable system (the main functionality of the system must be valid for each config).
In the other test case:
public TestClass2 extends BaseTests {
#Before
public void setup(){
// TODO: other config
}
}
For example, there may be an encryption and decryption process where the sequence of encryption>decryption must be identified. On the other hand, there is a different algorithm to use while the test process is unique.

Logically, there is no reason to call one test method from another. Any tool that runs one test would just as easily all tests in the package. But if you need to, you'd call it like any other method in any other class.
What you most likely want to do, is perform some common setup for both test methods. You could put that code in a utility method in a common class, and invoke the common code in both tests.

Related

UnfinishedStubbingException when performing stubbing from a class other than the test class

I'm using PowerMock to mock a java.net.Inet4Address (amongst other things) to return a particular IP address (getHostAddress()), as well as whether or not it's loopback (isLoopbackAddress()). I find that if I perform the actual stubbing (PowerMock.doReturn(...).when(mock).methodToStub()) anywhere other than from within the test class or an immediately inner class I get an UnfinishedStubbingException.
The problem is most obvious if I try to perform two stubs. The first one passes without an exception, but the second one throws the exception because it thinks the first one was not finished. If I only perform the one stub then I see different errors depending on what I do after that, so it's definitely the first stub that's causing the problem.
Below is some code that demonstrates the problem.
TestClass.java
/* package, imports... */
#RunWith(PowerMockRunner.class)
#PrepareForTest({Inet4Address.class})
public class TestClass {
#Test
public void test() {
Inet4Address mocked = PowerMockito.mock(Inet4Address.class);
// Option 1: Do it from within this class - WORKS
doStubbing(mocked);
// Option 2: Do it from an inner class - WORKS
Inner.doStubbing(mocked);
// Option 3: Do it from an inner class of the inner class - FAILS
Inner.Deeper.doStubbing(mocked);
// Option 4: Do it from an entirely different class - FAILS
OtherClass.doStubbing(mocked);
}
private void doStubbing(Inet4Address mocked) {
PowerMockito.doReturn(true).when(mocked).isLoopbackAddress();
PowerMockito.doReturn("127.0.0.1").when(mocked).getHostAddress();
}
public static class Inner {
static void doStubbing(Inet4Address mocked) {
PowerMockito.doReturn(true).when(mocked).isLoopbackAddress();
PowerMockito.doReturn("127.0.0.1").when(mocked).getHostAddress();
}
public static class Deeper {
static void doStubbing(Inet4Address mocked) {
PowerMockito.doReturn(true).when(mocked).isLoopbackAddress();
PowerMockito.doReturn("127.0.0.1").when(mocked).getHostAddress();
}
}
}
}
OtherClass.java
/* package, imports... */
public class OtherClass {
public static void doStubbing(Inet4Address mocked) {
PowerMockito.doReturn(true).when(mocked).isLoopbackAddress();
PowerMockito.doReturn("127.0.0.1").when(mocked).getHostAddress();
}
}
I've put the creation of the mock at the start, common to all scenarios. It makes no difference if the mock is created from within the same class where the stubbing is being done. I've also made the methods static for ease of reading; the behaviour is the same if the classes are instantiated first.
I know there are workarounds so I can get my test working (perform the mocking right there in the test class, mock the InetAddress interface instead of the IPv4 implementation, etc) but I'd like to know why PowerMock is behaving in this way. I could almost understand it if it only worked from within the test class, but why does it work in an inner class as well?

Ignore JUnit tests if variable value is null

I have a JUnit test class which runs 15 tests. 5 of the tests are optional in that I only wish to run them if a particular variable gets initialized by an argument. If the variable value is null I'd like to ignore these tests. Is this possible and if so, how?
You could use JUnit4's Assume feature ...
It's good to be able to run a test against the code as it is currently written, implicit assumptions and all, or to write a test that exposes a known bug. For these situations, JUnit now includes the ability to express "assumptions"
For example:
#Before
public void setUp() {
org.junit.Assume.assumeTrue(yourCondition());
// ...
}
If yourCondition() does not return true then the test for which #Before is running will not be executed.
Approach 1:
You can use JUnit-ext. It has RunIf annotation that performs conditional tests, like:
#Test
#RunIf(DatabaseIsConnected.class)
public void calculateTotalSalary() {
//your code there
}
class DatabaseIsConnected implements Checker {
public boolean satisify() {
return Database.connect() != null;
}
}
Approach 2
Another approach is to use Assume. You can do it in a #Before method or in the test itself, but not in an #After method. If you do it in the test itself, your #Before method will get run. You can also do it within #BeforeClass to prevent class initialization. For example:
#Before
public void beforeMethod() {
org.junit.Assume.assumeTrue(someCondition());
}
Approach 3
I think an another option for you may be to create an annotation to denote that the test needs to meet your custom criteria, then extend the default runner with your own and using reflection, base your decision on the custom criteria. It may look something like this:
public class CustomRunner extends BlockJUnit4ClassRunner {
public CTRunner(Class<?> klass) throws initializationError {
super(klass);
}
#Override
protected boolean isIgnored(FrameworkMethod child) {
if(shouldIgnore()) {
return true;
}
return super.isIgnored(child);
}
private boolean shouldIgnore(class) {
/* some custom criteria */
}
}

Run specific unit test according to condition

I have a test class containing test cases for say blue and non-blue devices. If the parameter isBlue is set then it should run only those test case that have say the #Blue annotation. I am not sure how to implement this specific annotation that will achieve this functionality.
public class TestClass {
boolean isBlue = false;
#Before
public void setUp () {
isBlue = MyApplication.instance().isBlue();
}
#Test
public void testA () { ... }
#Test #Blue
public void testB() { ... }
}
In this example if isBlue is true then it should only run testB() otherwise it should run all test cases
Take a look at JUnit runners. Nice explanation of runners
You can create your own runner which will extend on BlockJUnit4ClassRunner.
You can override
#Override
protected List<FrameworkMethod> getChildren() {
// scan test class for methonds annotated with #Test
}
To additionally filter by methods that have your custom annotation set, and your property in the application is set as well.
I think you are on the wrong path.
You want your test cases to help identifying problems; and assist you in fixing them. Anything that "distracts" you from that purpose reduces the values of your unit tests.
Thus: don't put tests that have really "different" scope into the same test class. Especially from the point of view: how would you control what "MyApplication.instance()" would return? That sounds like a problem in itself.
Meaning: you want to have two independent tests; and those don't rely on some "static" object telling them something. They test what is in their scope; nothing else.
By using jUnit Assume
#Test
public void testA () {
assumeTrue(MyApplication.instance().isBlue());
...
}
A failing assumption in a #Before or #BeforeClass method will have the same effect as a failing assumption in each #Test method of the class.

JUNIT : run setup only once for a large number of test classes

I have a class, which I use as a basis for my unit tests. In this class I initialize the whole environment for my tests, setting up database mappings, enter a number of database records across multiple tables, etc. That class has a method with a #BeforeClass annotation which does the initialization. Next thing, I extend that class with specific classes in which I have #Test methods.
My question is, since the before class is exactly the same for all these test classes, how can I ensure that they are run only once for all the tests.
One simple solution is that I could keep all the tests in one class. However, the number of tests is huge, also they are categorised based on functional heads. So they are located in different classes. However since they need the exact same setup, they inherit the #BeforeClass. As a result the whole setup is done at least once per test class, taking much more time in total than I would prefer.
I could, though, put them all in various subpackages under one package, hence if there is a way, how I can run set up once for all the tests within that package, it would be great.
With JUnit4 test suite you can do something like this :
#RunWith(Suite.class)
#Suite.SuiteClasses({ Test1IT.class, Test2IT.class })
public class IntegrationTestSuite
{
#BeforeClass
public static void setUp()
{
System.out.println("Runs before all tests in the annotation above.");
}
#AfterClass
public static void tearDown()
{
System.out.println("Runs after all tests in the annotation above.");
}
}
Then you run this class as you would run a normal test class and it will run all of your tests.
JUnit doesn't support this, you will have to use the standard Java work-arounds for singletons: Move the common setup code into a static code block and then call an empty method in this class:
static {
...init code here...
}
public static void init() {} // Empty method to trigger the execution of the block above
Make sure that all tests call init(), for example my putting it into a #BeforeClass method. Or put the static code block into a shared base class.
Alternatively, use a global variable:
private static boolean initialize = true;
public static void init() {
if(!initialize) return;
initialize = false;
...init code here...
}
Create one base class for all tests:
public class BaseTest {
static{
/*** init code here ***/
}
}
and every test should inherit from it:
public class SomeTest extends BaseTest {
}
You can make one BaseTest class with a #BeforeClass method, then have all the other tests inherit from it. This way, when each test object is constructed, #BeforeClass gets executed.
Also avoid executing it just once for all the test suite, since all the test cases should be independent. #BeforeClass should execute only once each test case, not test suite.
If you can tolerate adding spring-test to your project, or you are using it already, then a good approach is to use the technique described here: How to load DBUnit test data once per case with Spring Test
Not sure if anyone still is using JUnit and trying to fix it without using Spring Runner (aka no spring integration). TestNG has this feature. But here is a JUnit based solution.
Create a RunOnce per thread operation like so. This maintains a list of classes for which the operation has run.
public class RunOnceOperation {
private static final ThreadLocal t = new ThreadLocal();
public void run(Function f) {
if (t.get() == null) {
t.set(Arrays.asList(getClass()));
f.apply(0);
} else {
if (!((List) t.get()).contains(getClass())) {
((List) t.get()).add(getClass());
f.apply(0);
}
}
}
}
Back in your unit test
#Before
public beforeTest() {
operation.run(new Function<Integer, Void>() {
#Override
public Void apply(Integer t) {
checkBeanProperties();
return null;
}
});
}
private void checkBeanProperties() {
//I only want to check this once per class.
//Also my bean check needs instance of the class and can't be static.
}
My function interface is like this:
interface Function<I,O> {
O apply(I i);
}
When you use this way, you can perform operations once per class using ThreadLocal.

TestNG test inheritance and groups

We have DAO tests that should run against both the real DAO/database, and against a mock dao to verify that the mock dao behaves the same as the real dao. To this end, we have a structure like this:
public abstract class DAOTestBase
{
public void testSimple()
{
// dummy assertion
assertTrue(true, "Hello");
}
}
#Test(groups = "fast")
public class TestMockDAO extends DAOTestBase
{
// setUp/tearDown and helper methods for mock
}
#Test(groups = "slow")
public class TestDAO extends DAOTestBase
{
// setUp/tearDown and helper methods for real DB
}
Unfortunately this doesn't work - TestNG doesn't think that the testSimple method is a test and hence won't run it. So instead I tried to annotate the testSimple method (or the DAOTestBase class):
A #Test annotation without any groups will lead to the same effect - the test won't run for either fast nor slow groups.
A #Test annotation with groups fast and slow will lead to the opposite effect - both TestMockDAO and TestDAO will be run regardless of whether only fast or only slow tests should be run.
A #Test annotation with a different group, say common, plus added dependsOnGroups="common" annotations in both TestMockDAO and TestDAO will also not work unless common is included in the groups to run which leads again to case 2 above (both TestMockDAO and TestDAO are run).
In the end, what I'm looking for is a way to be able to define the group for the inherited tests in the sub class, but it seems as if the #Test annotation is only applied to test methods in that very same class, not also to inherited methods that don't have a #Test annotation. Is there any other way to achieve this (without overriding all methods in the sub classes) ?
I am currently working through a similar situation.
A way to make test cases run is to use something like:
#Test
public void someTest() {
TestNG testng = new TestNG();
testng.setTestClasses(new Class[] { SomeTests.class });
testng.run();
}
Reference: http://testng.org/doc/documentation-main.html#running-testng-programmatically
Unforunately I am currently unable to get it to report the test cases within SomeTests.
Have you tried simply adding a #Test annotation on top of DAOTestBase? Each subclass will override it with its own group and this should make the method in the base a test method.
I am using TestNG 6.14.3 version and I found a solution using priority annotation.
Example:
I have a base test class:
public class TestBase {
#Test(priority = 0)
public void testA() {
assertTrue(true, "testA");
}
}
And another extended test class:
public class Test2 extends TestBase {
#Test(priority = 1)
public void testB() {
assertTrue(true, "testB");
}
}
When I run Test2 test class, I obtain the following esult:
testA: true
testB: true
I solved it this way:
The methods in the base class are in "base" group, but need to check if the test have been initialized.
public abstract DaoTestBase {
private boolean initialized = false;
#Test(groups = "base")
public void testSimple() {
if (!initialized) { return; }
// dummy assertion
assertTrue(true, "Hello");
}
}
The test is initialized in the child, in the BeforeClass annotated method.
#BeforeClass
protected void initialize() {
super.initialized = true;
}
If you annotate the parent class instead of the methods, you must pass inheritGroups=false and the group, since it inherits also the group of the base class and it will not work.
Now, you must run TestNG to check groups base,fast or base,slow. Both tests will be executed, but the one not initialized will do nothing.
It is ugly, and I would not recommend it (it looks better to redefine the methods in child and call the according super method), but in my case I need priority in my test methods, and I want to avoid that repetition in each child class.

Categories

Resources