How launch of certain TestSuite using the parameter in jUnit? - java

I have test classes wich use other test classes. It is necessary to run these classes depending on the transferred parameter in Jenkins. (For example: if jenkins get parameter testOne then start testsuite testOne. If jenkins get parameter testOther then start testsuite testOther and so on)
How can I implement this in jUnit?
This is an example of one of the test suites:
#RunWith(Categories.class)
#Suite.SuiteClasses({UserLogin.class,
ExampleTests.class
}
)
public class FirstTest {

I believe you can do something like that using junit test categories. For example, for running integration tests, you can configure a separate annotation for the tests.
Maven supports test categories.
Does it solve your problem or is the jenkins input parameter critical? If it is a jenkins parameter, I believe it is some environment/build configuration and you can customize your build (maven tests to be run) as per the the environment or build job.

Related

How can I use a custom runner when using categories in Junit?

I have a bunch of JUnit tests that extend my base test class called BaseTest which in turn extends Assert. Some of my tests have a #Category(SlowTests.class) annotation.
My BaseTest class is annotated with the following annotation #RunWith(MyJUnitRunner.class).
I've set up a Gradle task that is expected to run only SlowTests. Here's my Gradle task:
task integrationTests(type: Test) {
minHeapSize = "768m"
maxHeapSize = "1024m"
testLogging {
events "passed", "skipped", "failed"
outputs.upToDateWhen {false}
}
reports.junitXml.destination = "$buildDir/test-result"
useJUnit {
includeCategories 'testutils.SlowTests'
}
}
When I run the task, my tests aren't run. I've pinpointed this issue to be related to the custom runner MyJUnitRunner on the BaseTest. How can I set up my Gradle or test structure so that I can use a custom runner while using the Suite.
The solution to this turned out to smaller and trickier than I thought. Gradle was using my custom test runner and correctly invoking the filter method. However, my runner reloads all test classes through its own classloader for Javaassist enhancements.
This lead to the issue that SlowTest annotation was loaded through the Gradle classloader but when passed to my custom runner, the runner checked if the class was annotated with that annotation. This check never resolved correctly as the equality of the SlowTest annotation loaded through two different classloaders was different.
--
Since I've already done the research, I'll just leave this here. After days of digging through the Gradle and the (cryptic) JUnit sources, here's what I got.
Gradle simply doesn't handle any advanced JUnit functionality except the test categorization. When you create a Gradle task with the include-categories or the exclude-categories conditions, it builds a CategoryFilter. If you don't know, a Filter is what JUnit gives to the test-runner to decide whether a test or a test method should be filtered out. The test runner must implement the Filterable interface.
JUnit comes with multiple runners, the Categories is just another one of them. It extends a family of test runners called Suite. These suite based runners are designed to run a "suite" of tests. A suite of tests could be built by annotation introspection, by explicitly defining tests in a suite or any other method that builds a suite of tests.
In the case of the Categories runner, JUnit has it's own CategoryFilter but Gradle doesn't use that, it uses it's own CategoryFilter. Both provide more or less the same functionality and are JUnit filters so that can be used by any suite that implements Filterable.
The actual class in the Gradle responsible for running the JUnit tests is called JUnitTestClassExecuter. Once it has parsed the command line options it requests JUnit to check the runner should be used for a test. This method is invoked for every test as seen here.
The rest is simply up to JUnit. Gradle just created a custom RunNotifier to generate the standard XML files representing test results.
I hope someone finds this useful and saved themselves countless hours of debugging.
TLDR: You can use any runner in Gradle. Gradle has no specifics pertaining to runners. It is JUnit that decided the runners. If you'd like to know what runner will be used for your test, you can debug this by calling
Request.aClass(testClass).getRunner(). Hack this somewhere into your codebase and print it to the console. (I wasn't very successful in attaching a debugger to Gradle.)

Why are JUnit tests run twice from within Eclipse?

A similar question has already been asked here.
One (unaccepted) answer states:
the test class will always be started directly and then through the
"link" in the suite. This is as expected.
Can someone explain what this actually means and whether or not it is possible to prevent the tests running twice.
When I run the tests from the command line using mvn test they only run once.
UPDATE
I have a test suite defined as follows:
#RunWith(Suite.class)
#SuiteClasses({ TestCase1.class, TestCase2.class })
public class MyTestSuite
{
}
When you run tests in Eclipse on project level (or package level), Eclipse searches all project's source folders for JUnit classes (or selected package). These are all classes with #Test annotations and all classes with #RunWith (probably some more too). Then for all these classes it runs them as tests.
As a result of this behavior, if you have a suite class that references tests classes in the same project, these tests will run twice. If you had another suite that did the same, they would run three times and so on. To understand this behavior try running a suite that contains one test case twice, for instance:
#RunWith(Suite.class)
#SuiteClasses({ TestCase1.class, TestCase1.class })
public class TestSuite {}
Accepted strategy here is to define a suite or suites for a project an run them exclusively. Do not start tests on a project level but run selected suites only.
As far as Maven is concerned, I suspect that its default configuration only picks out suite class and omits test cases. Had it been configured differently, it would behave the same as Eclipse.
Elipse tests 2 classes and give you 2 results.
Maven tests 2 classes and give you one result with 2 sub results.
I think is somethink like this, but still most important thing is that result are
positive! :)
Regards!
Same as this question https://github.com/spring-projects/spring-boot/issues/13750
Just exclude individual test cases and include the suite test cases.

TestNG running JUnit tests but not reporting all results

Background:
I have a a series of 172 integration tests that have been written using JUnit. Since our project needed to have them run on an embedded arm chip the tests have to be compiled into a jar and run using the command line. We realized after writing the tests that JUnit did not support xml output as part of the default library (which we required for jenkins). We added TestNG to our project because it provided a simple way to output XML results for our JUnit tests.
We are using the following command to run our tests:
/usr/local/frc/JRE/bin/java -ea -jar wpilibJavaIntegrationTests-0.1.0-SNAPSHOT.jar -junit -testclass edu.wpi.first.wpilibj.test.TestSuite
Where TestSuite is a bit like this:
#RunWith(Suite.class)
#SuiteClasses({
WpiLibJTestSuite.class,
CANTestSuite.class,
CommandTestSuite.class,
SmartDashboardTestSuite.class
})
public class TestSuite{
static{
//Some basic java.util.logging setup stuff
}
}
Each suite listed has its own set of test classes listed in a similarly formatted class.
Problem:
All 172 tests are being run by TestNG however it is only reporting 81 tests run and not reporting some failures (there were really two tests that failed but only one was reported).
===============================================
Command line suite
Total tests run: 81, Failures: 1, Skips: 8
===============================================
It seems that that unreported tests are the ones #RunWith(Parameterized.class)
Is there any way to get TestNG to properly recognize these tests and report their results appropriately?
You will have to change it to the TestNG way of doing it. (You should probably scan your code for imports from junit and replace them with corresponding TestNG constructs.)
This can be easily done, as most of the assertion statements are nearly identical to the JUnit ones (in fact several frameworks exist for automatically converting all tests to TestNG), and the test classes can be stripped of their direct inheritance from JUnit.
To do this in TestNG you'll need to annotate your test method with a data provider:
#Test(dataProvider = "MyProvider")
public void testSomeStuff() {}
and then implement a corresponding provider using either a 2D array (if your test cases are small and already known):
#DataProvider(name = "MyProvider")
public Object[][] myDataProvider() {}
or by using the following if your test cases are large or unknown:
#DataProvider(name = "MyProvider")
public Iterator<Object[]> myDataProvider() {}
This article may be helpful for understanding the differences between JUnit and TestNG.

Maven Surefire: run a single unit test

I know that it's possible to run a specific test class with -Dtest=MyTest. But is it possible to run a specific test within that class?
I.e. if MyTest defines testFoo() and testBar(), is there a way to specify that only testfoo() should be run?
I'm aware that it's trivially easy to do this in an IDE, but I occasionally need to run tests on the command line on another server.
From Running a Single Test Using Maven Surefire Plugin
With version 2.7.3, you can run only n tests in a single Test Class.
NOTE : it's supported for junit 4.x and TestNG.
You must use the following syntax
mvn -Dtest=TestCircle#mytest test
You can use patterns too
mvn -Dtest=TestCircle#test* test
It will be available as of Surefire 2.8, see SUREFIRE-577
Don't think its available. You can work around it by passing some system properties & ignore execution of tests based on the property value. However it does not seem to add a great value add. There is also TestNG which offers additional features.
http://maven.apache.org/plugins/maven-surefire-plugin/examples/testng.html
To execute one Test at a time, run mvn test
mvn -Dtest=MyUnitlTest test
To execute one Test at a time and a specific method from it:
mvn -Dtest=MyUnitTest#method test
where MyUnitTest is the name of your test and #method is the name of your method.
Execute tests with surefire:
mvn surefire:test

Run JUnit Test suite from command line

How do I run a Junit 4.8.1 Test suite from command line ?
Also I want to use the categories introduces with JUnit 4.8 , is there a way where
I can specify from command line the category which I want to run.
Using java run JUnitCore class (also see here).
Categories are supposed to be used with test suites with #RunWith(Categories.class)
, #IncludeCategory and #ExcludeCategory. I am not aware of any dynamic way to use categories to run tests but I'd like to know of such it it exists. You can have pre-defined test suites for certain categories to run them.
There is no way (as of 4.8) to specify categories from the command line.
I can suggest two approaches:
1. Create Ant file with junit target and then invoke this target from commend line.
2. Implement test suite class, in it in some class with main() method. So you will be able to run it.
In 4.10, we do this:
mvn verify -p(your profiles) -Dit.test=(SuiteClass)
where SuiteClass is an empty class (no methods or fields) that is annotated with #RunWith(Categories.class) and #Suite.SuiteClasses({FooIT.class, BarIT.class, ...}). FooIT and BarIT are the integration tests.

Categories

Resources