If I have an arbitrary class that defines a JUnit test method, and a child class that overrides test behavior but not the actual test method itself, is it possible to run the ChildClass test directly in IntelliJ?
class ParentClass
{
#Test
public void testSomeBehavior()
{
doTest();
}
protected void doTest()
{
// ParentClass specific behavior
}
}
class ChildClass extends ParentClass
{
#Override
protected void doTest()
{
// ChildClass specific behavior
}
}
My current work around is to kick off a run at the class level (ChildClass), kill the run, and then manually select my test from the Run/Debug screen. But this is not ideal.
I do know if my parent class was defined as abstract then IntelliJ will give me a list of possible implementing classes that can run the given test. But I do not see that option when parent class is instantiable.
I don't understand why could you want to do it...
It is not recommended. But if you are interesting to create nested tests using JUNIT5 maybe you can use this documentation.
https://junit.org/junit5/docs/current/user-guide/#writing-tests-nested
Related
I have multiple production classes "NaiveHandler", "SmartHandler", "AnotherHandler" that implement the same interface "Handler" and share a lot of code. To reduce code duplication, I extracted an abstract class "AbstractHandler" that contains most of the code, and let the sub-classes inherit and reuse it.
Similarly, the test classes "NaiveHandlerTest", "SmartHandlerTest", "AnotherHandlerTest" for those production classes held tons of duplicate test methods. I moved all these #Test-annotated methods and the test setup out into an abstract class called "HandlerTestBase".
abstract class HandlerTestBase {
protected Handler cut;
protected SomeDependency x;
protected abstract Handler getCutInstance(SomeDependency x);
#BeforeEach
void setup() {
x = Mockito.mock(SomeDependency.class);
cut = getCutInstance(x);
}
#Test
void providesTheRightThing() {
when(x.getSomeValue()).thenReturn("zzz");
var result = cut.doSomething("a");
assertThat(result).isEqualTo("b");
}
// more tests that verify the shared code in AbstractHandler
}
This abstract class cannot (and should not) run on its own. The "~Base" at the end prevents Maven's tools from picking it up and running it. Instead, Maven picks up the individual test classes "NaiveHandlerTest", "SmartHandlerTest", "AnotherHandlerTest", and runs those.
class SmartHandlerTest extends HandlerTestBase {
#Override
protected Handler getCustInstance(SomeDependency x) {
return new SmartHandler(x);
}
// here more tests that only relate to SmartHandler, not the shared code, e.g.
#Test
void specificClassDoesTheRightThing() {
when(x.getSomeValue()).thenReturn("12345");
var result = cut.doSomething("a");
assertThat(result).isEqualTo("y");
}
}
All of this works beautifully.
As one consequence however, one of the test sub-classes, "NaiveHandlerTest" is now empty. It inherits the tests from the abstract class and runs those, but doesn't add any specific tests of its own. For me, this is not a problem.
class NaiveHandlerTest extends HandlerTestBase {
#Override
protected Handler getCustInstance(SomeDependency x) {
return new NaiveHandler(x);
}
}
However, SonarQube picks out this class and reports the code smell "Add some tests to this class", saying that "There's no point in having a JUnit TestCase without any test methods." For other cases, I would agree, but in this pattern SonarQube does not recognize that the test class may look empty but inherits and runs test methods from its super-class.
I could set this finding to "False Positive" to remove it. I could also annotate the seemingly empty test class with #java.lang.SuppressWarnings("java:S2187") to switch off this check here. Is there a still better way to get rid of this finding, such as a tiny tweak to the design that makes SonarQube aware of the existing tests?
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
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.
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).
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.