How to avoid inheritance in JUnit test cases? - java

I have a number of test cases in JUnit. All of them need the same code to be executed in their #BeforeClass static method. It's a code duplication and I'm trying to get rid of it. A dirty way of doing this is by inheritance. Are there any other mechanisms in JUnit, that may help?
PS. I wrote this blog post about this very subject: http://www.yegor256.com/2015/05/25/unit-test-scaffolding.html

The JUnit way to compose reusable code (instead of inheriting from it) are Rules.
See https://github.com/junit-team/junit/wiki/Rules
Here is a dumb sample, but you'll get the point.
import org.junit.rules.TestRule;
import org.junit.runners.model.Statement;
import org.junit.runner.Description;
public class MyTestRule implements TestRule {
#Override
public Statement apply(final Statement statement, Description description) {
return new Statement() {
public void evaluate() throws Throwable {
// Here is BEFORE_CODE
try {
statement.evaluate();
} finally {
// Here is AFTER_CODE
}
}
};
}
}
You can then use your TestRule like this:
import org.junit.Rule;
public class MyTest {
#Rule
public MyTestRule myRule = new MyTestRule();
}
BEFORE_CODE and AFTER_CODE will then be executed around each of your test methods.
If you need to run your code only once per class, use your TestRule as a #ClassRule:
import org.junit.ClassRule;
public class MyTest {
#ClassRule
public static MyTestRule myRule = new MyTestRule();
}
Now, BEFORE_CODE and AFTER_CODE will be executed around each of your test class.
#Rule field is not static, #ClassRule field is.
A #ClassRule can be declared in a Suite too.
Note that you can declare several rules in a single test class, that's how you compose test lifecycles at test-suites, test-classes and test-methods levels.
A Rule is an object that you instanciate in your test classes (statically or not). You can add contructor parameters if needed.
HTH

If the method is some kind of utility, then separate it out to a different class with a static method and call that method in your #BeforeClass.
I emphasize on the fact that don't use inheritance just because it solves your problem, use it when doing so creates sense in your class hierarchy.

You may create test runner
public class MyTestRunner extends BlockJUnit4ClassRunner {
#Override
protected Object createTest() throws Exception {
Object test = super.createTest();
doStuff();
}
public void doStuff(){
//common code
}
}
#RunWith(MyTestRunner.class)
public class MyTest1{
#Test
public void test1(){
//test method
}
}

Static methods aren't inherited, so inheritance isn't an option by default. If you mean you're moving the method to a common parent class, then that seems a poor choice since you only get one parent in Java. A test support class of some sort would seem more appropriate. It's also possible that you're seeing a need for a parameterized test.

There is absolutely nothing wrong with inheritance in this case, it's actually the only way to avoid repeating this code in each subclass. The fact that #BeforeClass methods have to be declared static in JUnit is unfortunate, but that shouldn't stop you. Extend the class and you have the initialization code automatically run for you without having to do anything.

If each and every class needs to have a #BeforeClass annotated method that is exactly the same as every other, then inheritance does not feel that wrong to me. If each of these initializing methods simply share some code, you could make a TestUtil class with some shared behavior and make calls to this shared behavior from each of the #BeforeClass methods.

I think if the classes has "is-a" relation, inheritance is reasonable.
If the base class is MyBeforeClass which defines #BeforeClass method, and MyTestClass1 "is-a" MyBeforeClass, MyTestClass1 extends MyBeforeClass is OK.

Depending on the nature of the setup code, you can potentially put all your tests in a test suite and have the setup code run there. The downside to this is that you cannot run tests individually (since the test depends on the setup code).

Related

How to reuse method and test in JUnit?

I've tried to avoid duplicate code in JUnit test, but I'm kind of stuck.
This is my first test, for the second one it has exactly the same methods but different service (different input). instead of the TestCaseResourceTest1 I have TestCaseResourceTest2. Now what could be the proper way to test both? I want to have a separate file for test number 2, how should I avoid the duplicate code? (ex. use the beforeFileTest() method)
public class TestCaseResourceTest1 {
#Mock
private TestService testService;
#Mock
private AreaService areaService;
private TestCaseService1 testCaseService1; // is changed in test2
#Before
public void before() throws Exception{
testCaseService1 = mock(TestCaseService1.class); // is changed in test2
MockitoAnnotations.initMocks(this);
beforeFileTest();
}
private void beforeFileTest() throws Exception{
doReturn(true).when(areaService).chechExists(any(String.class), eq(false));
}
#Test
public void verifyFileExists() throws Exception{
verifyOtherArea(testCaseService1); // is changed in test2
doReturn(false).when(areaService).chechExists(any(String.class), eq(false));
}
}
just lines with comment is changed in test2 are differences.
Tnx
Given this excerpt from your question:
… instead of the TestCaseResourceTest1 I have TestCaseResourceTest2 … I want to have a separate file for test number 2
… the standard ways of sharing code between test cases are:
Create a Test Suite and include the shared code in the test suite (typically in #BeforeClass and #AfterClass methods). This allows you to (1) run setup code once (per suite invocation); (2) encapsulate shared setup/teardown code and (3) easily add more tests cases later. For example:
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestCaseResourceTest1.class,
TestCaseResourceTest2.class
)}
public class TestSuiteClass {
#BeforeClass
public void setup() {
beforeFileTest();
}
private void beforeFileTest() throws Exception {
// ...
}
}
Create an abstract class which parents TestCaseResourceTest1 and TestCaseResourceTest2 and let those test cases call the shared code in the parent (typically via super() calls). With this approach you can declare default shared code in the parent while still allowing sub classes to (1) have their own behaviour and (2) selectively override the parent/default behaviour
Create a custom JUnit runner, define the shared behaviour in this runner and then annotate the relevant test cases with #RunWith(YourCustomRunner.class). More details on this approach here
Just to reiterate what some of the other posters have said; this is not a common first step so you may prefer to start simple and only move to suites or abstract classes or custom runners if your usage provides a compelling reason to do so.
I had the such situation and it was a sign about wrong implementation design. We are talking about pure unit tests where we test exactly what is implemented in the production classes. If we need duplicated tests it means we probably have duplication in implementation.
How did I resolve it in my project?
Extracted common logic into parent service class and implemented unit tests for it.
For child services I implemented tests only for particular implemented code there. No more.
Implemented an integration tests on real environment were both services were involved and tested completely.
Assuming you want to have the exact same test run for 2 different classes (and not mocking it as in your example code), you can create an abstract test class, that has abstract method that returns an instance of the class to be tested.
Something in the vein of:
public abstract class TestCaseResourceTest {
protected abstract TestCaseService1 getServiceToTest();
#Before
public void before() throws Exception {
testCaseService1 = getServiceToTest();
MockitoAnnotations.initMocks(this);
beforeFileTest();
}
#Test
public void test() {
// do your test here
}
}
public class ConcreteTest extends TestCaseResourceTest {
protected TestCaseService1 getServiceToTest() {
return new TestCaseService();
}
}
public class ConcreteTest2 extends TestCaseResourceTest {
protected TestCaseService1 getServiceToTest() {
return new DifferentService();
}
}
Have you considered using JUnit 5 with its http://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests ?
It allows you to re-use your tests with different input. This is an example from the documentation which illustrates what you can do now with JUnit 5:
#ParameterizedTest
#ValueSource(strings = { "Hello", "World" })
void testWithStringParameter(String argument) {
assertNotNull(argument);
}
But you can also create your methods which return the input data:
#ParameterizedTest
#MethodSource("stringProvider")
void testWithSimpleMethodSource(String argument) {
assertNotNull(argument);
}
static Stream<String> stringProvider() {
return Stream.of("foo", "bar");
}
Here I am using just strings, but you can really use any objects.
If you are using Maven, you can add these dependencies to start using JUnit 5:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.0.0-RC2</version>
<scope>test</scope>
</dependency>
The only annoying thing about JUnit 5 is that it is not released yet.
When going from one test to two tests, you don't know what will be duplicate code, so I find it useful to put everything into one test method. In this case, start by putting the contents of the #Before and beforeFileTest methods inline in the test.
Then you can see that it is just te service that needs changing, so you can extract everything except that into a helper method that is called from two tests.
Also, after you have two tests that are calling the same helper method and are happy with that test coverage, you could look into writing parameterized tests. For example with JunitParams: https://github.com/Pragmatists/junitparams/wiki/Quickstart

Non static #BeforeClass equivalent when Spring unit test runner? [duplicate]

Are there any best practices to get Junit execute a function once in a test file , and it should also not be static.
like #BeforeClass on non static function?
Here is an ugly solution :
#Before void init(){
if (init.get() == false){
init.set(true);
// do once block
}
}
well this is something i dont want to do , and i am looking for an integrated junit solution.
A simple if statement seems to work pretty well too:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:test-context.xml"})
public class myTest {
public static boolean dbInit = false;
#Autowired
DbUtils dbUtils;
#Before
public void setUp(){
if(!dbInit){
dbUtils.dropTables();
dbUtils.createTables();
dbInit = true;
}
}
...
To use an empty constructor is the easiest solution. You can still override the constructor in the extended class.
But it's not optimal with all the inheritance. That's why JUnit 4 uses annotations instead.
Another option is to create a helper method in a factory/util class and let that method do the work.
If you're using Spring, you should consider using the #TestExecutionListeners annotation.
Something like this test:
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({CustomTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class})
#ContextConfiguration("test-config.xml")
public class DemoTest {
Spring's AbstractTestExecutionListener contains for example this empty method that you can override:
public void beforeTestClass(TestContext testContext) throws Exception {
/* no-op */
}
NOTE: DO NOT overlook/miss DependencyInjectionTestExecutionListener while adding custom TestExecutionListeners. If you do, all the autowires will be null.
If you don't want to set up static initializers for one time initialization and are not particular about using JUnit, take a look at TestNG. TestNG supports non-static, one-time initialization with a variety of configuration options, all using annotations.
In TestNG, this would be equivalent to:
#org.testng.annotations.BeforeClass
public void setUpOnce() {
// One time initialization.
}
For teardown,
#org.testng.annotations.AfterClass
public void tearDownOnce() {
// One time tear down.
}
For the TestNG equivalent of JUnit 4's #Before and #After, you can use #BeforeMethod and #AfterMethod respectively.
Easily use #BeforeAllMethods/#AfterAllMethods annotations to run a method inside the instance context (non-static), where all injected values will be available.
There is a special testing library for this:
https://mvnrepository.com/artifact/org.bitbucket.radistao.test/before-after-spring-test-runner/0.1.0
https://bitbucket.org/radistao/before-after-spring-test-runner/
The only limitation: works only for Spring testing.
(I'm the developer of this testing library)
I've never tried but maybe you can create a no-argument constructor and call you function from there?
The article discuss 2 very nice solutions for this problem:
"clean" junit with custom Runner (using interface but you could extend it with a custom annotation e.g. #BeforeInstance)
Spring execution listeners as mentioned by Espen before.
UPDATE: Please see the comment by Cherry for why the suggestion below is flawed. (Am keeping the answer on here rather than deleting as the comment may provide useful information to others as to why this doesn't work.)
Another option worth considering if using dependency injection (e.g. Spring) is #PostConstruct. This will guarantee dependency injection is complete, which wouldn't be the case in a constructor:
#PostConstruct
public void init() {
// One-time initialization...
}
Just use #BeforeClass:
#BeforeClass
public static void init() {
}
It doesn't make sense for init to be non-static because each test is run in a separate instance. The instance
that init is run on would not match the instance of any test.
The only reason that you might want it to be non-static is to override it in subclasses, but you can do this
with static methods too. Just use the same name, and only the subclass init method will be called.

Mock System class to get system properties

I have a folder path set in system variable through JVM arguments in Eclipse and I am trying to access it in my class as:
System.getProperty("my_files_path").
While writing junit test method for this class, I tried mocking this call as test classes do not consider JVM arguments. I have used PowerMockito to mock static System class and tried returning some path when System.getProperpty is being called.
Had #RunWith(PowerMockRunner.class) and #PrepareForTest(System.class) annotations at class level. However, System class is not getting mocked as a result I always get null result.
Any help is appreciated.
Thanks Satish. This works except with a small modification. I wrote PrepareForTest(PathFinder.class), preparing the class I am testing for test cases instead of System.class
Also, as mock works only once, I called my method right after mocking.
My code just for reference:
#RunWith(PowerMockRunner.class)
#PrepareForTest(PathInformation.class)
public class PathInformationTest {
private PathFinder pathFinder = new PathFinder();
#Test
public void testValidHTMLFilePath() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty("my_files_path")).thenReturn("abc");
assertEquals("abc",pathFinder.getHtmlFolderPath());
}
}
There are certain classes PowerMock can't mock in the usual way. See here:
https://code.google.com/p/powermock/wiki/MockSystem
This, however, may still not work. In order of "good design" preference, you can fall back to these:
Refactor your code! Using a System property for passing a file path around is probably not the best way. Why not use a properties file loaded into a Properties object? Why not use getters/setters for the components that need to know this path? There are many better ways to do this.
The only reason I could think of not to do this is you're trying to wrap a test harness around code you "can't" modify.
Use #Before and #After methods to set the System property to some known value for the test(s). You could even make it part of the #Test method itself. This will be FAR easier than attempting to mock through PowerMock. Just call System.setProperty("my_files_path","fake_path");
System class is declared as final and cannot be mocked by libraries such as PowerMock. Several answers posted here are incorrect. If you are using Apache System Utils you can use getEnvironmentVariable method instead of calling System.getenv directly. SystemUtils can be mocked since it is not declared as final.
Set the system property in your test and ensure that it is restored after the test by using the rule RestoreSystemProperties of the library System Rules.
public class PathInformationTest {
private PathFinder pathFinder = new PathFinder();
#Rule
public TestRule restoreSystemProperties = new RestoreSystemProperties();
#Test
public void testValidHTMLFilePath() {
System.setProperty("my_files_path", "abc");
assertEquals("abc",pathFinder.getHtmlFolderPath());
}
}
The System.setter or getter method should be put in a user defined method and that method can be mocked to return the desired property in unit test.
public String getSysEnv(){
return System.getEnv("thisprp");
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(System.class)
public class MySuperClassTest {
#Test
public void test(){
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty("java.home")).thenReturn("abc");
System.out.println(System.getProperty("java.home"));
}
}
Sailaja add System.class because as per the power mock guidelines for static,private mocking you should add the class in prepare for test.
#PrepareForTest({PathInformation.class,System.class})
Hope this helps.let me know if it doesn't work

suppress a singleton constructor in java with powermock

I'm trying to unit-test some classes that make use of a Singleton class whose constructor does some things I can't (and shouldn't) do from the unit-test environment. My ideal scenario would be to end up with the constructor completely suppressed and then stub out the other member methods that my test classes invoke. My problem is that I can't seem to get the constructor suppressed.
My understanding of a way to solve this would be something like the following:
public class MySingleton extends AbstractSingletonParent {
public final static MySingleton Only = new MySingleton();
private MySingleton(){
super(someVar); // I want the super-class constructor to not be called
//
//more code I want to avoid
}
public Object stubbedMethod() {}
}
public class ClassToBeTested {
public void SomeMethod(){
Object o = MySingleton.Only.stubbedMethod();
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(MySingleton.class)
public class TestClass {
#Test
public void SomeTest() {
suppress(constructor(MySingleton.class));
mockStatic(MySingleton.class);
PowerMock.replay(MySingleton.class);
// invoke ClassToBeTested, etc
PowerMock.verify(MySingleton.class);
//make some assertions
}
}
Unfortunately during the createMock invocation, the MySingleton constructor is hit, and it still calls the super constructor.
Am I doing something silly? I found an example on the web doing almost exactly this, but it was using a deprecated suppressConstructor method. Despite the deprecation I tried that, too, to no avail...
Is what I'm trying to do possible? If so, what am I doing wrong?
*Edited version now works.
You need to annotate TestClass with the #PrepareForTest annotation so it has a chance to manipulate the bytecode of the singletons.
Also, the superclass ctor supression signature should include somevar's class; right now you're just suppressing the default ctor.
See the #PrepareForTest API docs. Here's a blog post with some more details as well.
FWIW, it's working for me:
#RunWith(PowerMockRunner.class)
#PrepareForTest({EvilBase.class, NicerSingleton.class})
public class TestEvil {
#Test
public void testEvil() {
suppress(constructor(EvilBase.class));
assertEquals(69, EvilBase.getInstance().theMethod());
}
#Test
public void testNice() {
suppress(constructor(EvilBase.class));
suppress(constructor(NicerSingleton.class));
assertEquals(42, NicerSingleton.getInstance().theMethod());
}
}
How about you set the instance field ('only' in your code) of your Singleton with an instance instantiated with the constructor you want (you can do all of this with the Reflection API or dp4j).
The motivating example of a dp4j publication discusses that.
I am not sure what is it that you are doing wrong. But on the design side, i can suggest you look into dependency injection i.e. DI.
For making your code testable, make use of DI. With DI you would pass the singleton class as an constructor argument to your test class. And now since you pass an argument, inside your test case you can create a custom implementation of the AbstractSingleton class and your test case should work fine.
With DI, your code will become more testable.

Is it possible to create a mock object that implements multiple interfaces with EasyMock?

Is it possible to create a mock object that implements several interfaces with EasyMock?
For example, interface Foo and interface Closeable?
In Rhino Mocks you can provide multiple interfaces when creating a mock object, but EasyMock's createMock() method only takes one type.
Is it possbile to achieve this with EasyMock, without resorting to the fallback of creating a temporary interface that extends both Foo and Closeable, and then mocking that?
Although I fundamentally agree with Nick Holt's answer, I thought I should point out that mockito allows to do what you ask with the following call :
Foo mock = Mockito.mock(Foo.class, withSettings().extraInterfaces(Bar.class));
Obviously you'll have to use the cast: (Bar)mock when you need to use the mock as a Bar but that cast will not throw ClassCastException
Here is an example that is a bit more complete, albeit totally absurd:
import static org.junit.Assert.fail;
import org.junit.Test;
import static org.mockito.Mockito.*;
import org.mockito.Mockito;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import org.hamcrest.Matchers;
import java.util.Iterator;
public class NonsensicalTest {
#Test
public void testRunnableIterator() {
// This test passes.
final Runnable runnable =
mock(Runnable.class, withSettings().extraInterfaces(Iterator.class));
final Iterator iterator = (Iterator) runnable;
when(iterator.next()).thenReturn("a", 2);
doThrow(new IllegalStateException()).when(runnable).run();
assertThat(iterator.next(), is(Matchers.<Object>equalTo("a")));
try {
runnable.run();
fail();
}
catch (IllegalStateException e) {
}
}
have you considered something like:
interface Bar extends Foo, Closeable {
}
and then mock interface Bar?
EasyMock doesn't support this so you're stuck with fallback of the temporary interface.
As an aside, I smell a little bit of a code wiff - should a method really be treating an object as 2 different things, the Foo and Closeable interface in this case?
This implies to me that the method is performing multiple operations and while I suspect one of those operations is to 'close' the Closeable, wouldn't it make more sense for the calling code to decide whether or not the 'close' is required?
Structuring the code this way keeps the 'open' and 'close' in the same try ... finally block and IMHO makes the code more readable not to mention the method more general and allows you to pass objects that only implement Foo.
An alternative of the most voted answer still based on Mockito but with annotations. You can set the extraInterfaces directly from the Mock annotation as next:
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Mock(extraInterfaces = Closeable.class)
private Foo foo;
...
}
NB: extraInterfaces is of type Class<?>[] so you can specify several interfaces if needed.
If you need to mock method calls of the extra interfaces you will need to cast your mock. For example let's say that I want to throw an IOException when I call close() on my mock foo, the corresponding code would then be:
Mockito.doThrow(IOException.class).when((Closeable) foo).close();
To the best of my knowledge, the only mocking tool for Java that has explicit support for mocking multiple interfaces is JMockit. (My inspiration for adding this feature came from Moq and Rhino Mocks, which are .NET tools.)
An example (from the mockit.ExpectationsUsingMockedTest JUnit 4 test class):
#Test
public <M extends Dependency & Runnable> void mockParameterWithTwoInterfaces(final M mock)
{
new Expectations()
{
{
mock.doSomething(true); returns("");
mock.run();
}
};
assertEquals("", mock.doSomething(true));
mock.run();
}
Dependency and Runnable are interfaces. The doSomething method belongs to the first, and run to the second.
Another way to solve this problem is to use a CGLib mixin:
final Interface1 interface1 = mockery.mock(Interface1.class);
final Interface2 interface2 = mockery.mock(Interface2.class);
service.setDependence(Mixin.create(new Object[]{ interface1, interface2 }));
mockery.checking(new Expectations(){{
oneOf(interface1).doSomething();
oneOf(interface2).doNothing();
}});
service.execute();
Whether or not this is a good idea, it's something up to discussion...

Categories