How to reuse method and test in JUnit? - java

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

Related

About unit-test dependency

I'm trying to code some basic unit-tests for a project I am currently working on where I have my service that has a method addPlaneModel to add a plane model (under the hood it adds a PlaneModel instance into a TreeMap and throws a custom exception if the TreeMap already contains the key).
I could write a test (for example shouldAddNewPlane_Succeed) to see if it's properly adding the PlaneModel but my problem comes if I wanted to create a test to see if the PlaneModel already existed (for example shouldAddNewPlane_ThrowExistingModelException because I should call addPlaneModel twice to make it throw the exception, but if shouldAddNewPlane_Succeed test doesn't run first, I don't really 'know' if that method works as it should.
I've read that unit-tests should be independant from each other but I can't really grasp how to do it in this case, do I necessarily have to run them in order?
You should be creating a new instance of the class you are testing before each test.
So your test class will look like:
class MyTests {
private MyService myService;
#Before // junit 4, or #BeforeEach for junit 5
public void setup() {
myService = new MyService(... pass mocks of dependencies ...);
}
#Test
public void aTest() {
myService...
}
#Test
public void aTest2() {
myService... // this is a fresh instance of MyService, any changes to the
// state of the instance used in aTest() are gone.
}
}
If you want to execute some common code before running a test, you can use the #Before method annotation in JUnit. For instance:
#Before
public void init() {
LOG.info("startup");
list = new ArrayList<>(Arrays.asList("test1", "test2"));
}
This code will always execute before any other test that you run. This is useful to define a certain order for execution to your tests.

how to initialize JUnit test classes before running in parallel

I am trying to execute JUnit tests in parallel using the ParallelComputer experimental feature, however I do not know how to pre-initialize each of the test classes before kicking off the tests.
The classic example of how these are supposed to be used is as follows (as shown in the following GitHub link). Per the example, how do I initialize the ParallelTest1 and ParallelTest2 classes with shared data before starting the parallel thread testing. I was able to do this via constructors in each of the classes, however I need to make sure that both classes are fully initialized before the run starts. This problem is probably not specific to the Parallel nature of how I wish to perform the testing but more likely how to use some special keywords to order prevent initialized objects from starting until required. Ideally the example ParallelComputerTest could have this shared data initialized in its constructor, however in that case, how could the nested static parallel test classes get access to this instance data?
public class ParallelComputerTest {
#Test
public void test() {
Class[] cls={ParallelTest1.class,ParallelTest2.class };
//Parallel among classes
JUnitCore.runClasses(ParallelComputer.classes(), cls);
//Parallel among methods in a class
JUnitCore.runClasses(ParallelComputer.methods(), cls);
//Parallel all methods in all classes
JUnitCore.runClasses(new ParallelComputer(true, true), cls);
}
public static class ParallelTest1{
#Test public void a(){}
#Test public void b(){}
}
public static class ParallelTest2{
#Test public void a(){}
#Test public void b(){}
}
}
Use #Before for set ups and #After for clean ups.
For example to test console output I set up streams before and clean result after test like this:
#Before
public void setUpStreams() {
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
}
#After
public void cleanUpStreams() {
System.setOut(null);
System.setErr(null);
}
NOTE: this can cause problems with TestSuite, dunno if also with ParallelTest. If you experience some troubles AND you use JUnit 4.7 or higher you might like to check this link to rules feature

How to make the unit test execute a particular test case everytime when it sees a certain function in the executing java project?

I am having a build failure issue while running a bunch of unit test over a java project. I am getting the NoClassDefFoundError which is happening because of the lack of ability for the unit test to get the dependencies. I am trying to mock an object for the class and then call the function, but the code is structured in a way that is getting a bit complex for me to handle the issue. I am very new to unit testing. I have provided below, a sample of code structure that my project has
Class ServiceProvider(){
obj declarations;
public void mainFunction(){
//Does a couple of things and calls a function in another class
boolean val = subFunction();
}
public boolean subFunction(){
boolean val = AnotherClass.someFunction(text);
//this function throws lots of exceptions and all those are caught and handled
return val;
}
#RunsWith(MockitoJUnitRunner.class)
Class UnitTestBunch(){
#Mock
AnotherClass acObj = new AnotherClass();
#InjectMock
ServiceProvider sp = new ServiceProvider();
#Test
public void unitTest1() throws Exception{
when(acObj.someFunction(text)).thenReturn(true);
}
#Test
public void unitTest2() throws Exception{
thrown.expect(ExceptionName.Class);
sp.mainFunction();
}
I have a test that uses the mock object and performs the function call associated with that class. But, the issue here is that there are a bunch of other unit test cases that are written similar to the unitTest2 function and calls the mainFunction at the end of the test. This mainFunction invokes someFunction() and causes NoCalssDefFoundError(). I am trying to make the unit test execute the content in unitTest1 everytime when it sees the AnotherClass.someFunction(). I am not sure if this is achievable or not. There could be another better way to resolve this issue. Could someone please pitch in some ideas?
In your test you seem to be using unitTest1 for setup, not for testing anything. When you run a unit test, each test should be able to run separately or together, in any order.
You're using JUnit4 in your tests, so it would be very easy to add the statement you have in unitTest1 into a #Before method. JUnit4 will call this method before each test method (annotated with #Test).
#Before
public void stubAcObj() throws Exception{
when(acObj.someFunction(text)).thenReturn(true);
}
The method may be named anything, though setUp() is a common name borrowed from a method to override in JUnit3. However, it must be annotated with org.junit.Before.
If you need this from multiple test cases, you should just create a helper, as you would with any code. This doesn't work as well with #InjectMocks, but you may want to avoid using #InjectMocks in general as it will fail silently if you add a dependency to your system-under-test.
public class AnotherClassTestHelper {
/** Returns a Mockito mock of AnotherClass with a stub for someFunction. */
public static AnotherClass createAnotherClassMock() {
AnotherClass mockAnotherClass = Mockito.mock(AnotherClass.class);
when(mockAnotherClass.someFunction(text)).thenReturn(true);
return mockAnotherClass;
}
}
As a side note, this is a counterintuitive pattern:
/* BAD */
#Mock
AnotherClass acObj = new AnotherClass();
You create a new, real AnotherClass, then instruct Mockito to overwrite it with a mock (in MockitoJUnitRunner). It's much better just to say:
/* GOOD */
#Mock AnotherClass acObj;

How do I re-use (include) Junit test block in other tests

I am fairly new to the JAVA world - coming from a ColdFusion background - and have been learning Java because I'm learning Selenium WebDriver /JUnit. I have written several test classes that test admin functionality that follow a similar structure.
public class myclass{
public static WebDriver driver;
#BeforeClass
public static void startDriver(){
driver = new FirefoxDriver();
driver.get("some url");
}
#Test
public void myLogin(){
some login code
}
#Test
public void somefunction() {
other admin function to test
}
My question is this - since all my tests require the user to log in - I end up having to re-use the "mylogin" test code over and over. How can I write the tests to simply "include" (like the "cfinclude" tag in ColdFusion) the login code so that if changes are made to the login page functionality - I only have to change it in one place.
Java hasn't got a lexical include statement like ColdFusion or C. This is by design, because just pasting sourcecode before compilation is a very unclean way of sharing code between modules.
But there are many other ways to approach this issue. Here are two:
Create your own library with commonly used functionality encapsulated in methods and use this library in your tests
Add setUp and tearDown methods for your test classes. These methods are executed before and after each one of your test methods. Note that test classes can inherit from each other. So when you have lots of test classes with identical setUp and tearDown methods, you can make them extend a common base class and implement these methods in the base class once.
You can implement the myLogin() functionality in a base parent class what you will need to extend in all of your test classes to access this functionality across various tests:
public abstract class MyBaseTest {
public void myLogin() {
<some login code>
}
}
public class MyClass extends MyBaseTest {
#Test
public void somefunction() {
super.myLogin();
}
}
You could use the #Before annotation to accomplish this. The annotated method will run before every #Test annotated method. Similarly you could use #After to logout after every unit test, if needed.

JUnit TestCase object instantiation

Is a new (or different) instance of TestCase object is used to run each test method in a JUnit test case? Or one instance is reused for all the tests?
public class MyTest extends TestCase {
public void testSomething() { ... }
public void testSomethingElse() { ... }
}
While running this test, how many instances of MyTest class is created?
If possible, provide a link to a document or source code where I can verify the behaviour.
Yes, a separate instance is created.
While running that test, 2 instances of MyTest gets created.
If you want a different behavior, one option is to use a similar tool called TestNG(http://testng.org/doc/).
I couldn't find a clear answer in the JUnit docs about your question, but the intent, as anjanb wrote, is that each test is independent of the others, so a new TestCase instance could be created for each test to be run.
If you have expensive test setup ("fixtures") that you want to be shared across all test cases in a test class, you can use the #BeforeClass annotation on a static method to achieve this result: http://junit.sourceforge.net/javadoc_40/org/junit/BeforeClass.html. Note however, that a new instance may still be created for each test, but that won't affect the static data your #BeforeTest method has initialized.
There's one instance for each test run. Try
public class MyTest extends TestCase {
public MyTest() { System.out.println("MyTest Constructor");
public void setUp() { System.out.println("MyTest setUp");
public void tearDown() { System.out.println("MyTest tearDown");
public void testSomething() { System.out.println("MyTest testSomething");
public void testSomethingElse() { System.out.println("MyTest testSomethingElse");
}
The Sourcecode (including that to newer versions - your and my example is Junit 3) is on http://www.junit.org
If you are asking this because you are concerned about data being initialized and re-initialized in your constructor, be aware that the prescribed way to initialize your test cases data is via setUp() and tearDown() exclusively.
Yes, definitely. I found that data I stored in instance variables could not be accessed between tests due to this design.

Categories