Why do multiple JUnit TestWatchers not spawn multiple test method calls? - java

I'm using multiple JUnit TestWatchers on each of the tests in my test suite. I was worried that each TestWatcher was calling base.evaluate() and each test was actually being run multiple times (once by each call to base.evaluate()). That does not seem to be happening, which is great, but I'm confused as to why that is the case.
Why don't multiple JUnit TestWatchers in a single test result in multiple calls to the test method?
I think I have some fundamental misunderstanding of how these components (in particular base.evaluate()) interact, but haven't found any good explanations that have resolved this confusion on my part.
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class SimpleTest {
#Rule
public TestWatcher testWatcher1 = new TestWatcher() {
#Override
public Statement apply(Statement base, Description description) {
return new Statement() {
public void evaluate() throws Throwable {
try {
System.out.println("testWatcher1");
base.evaluate();
} catch (Throwable e) {
e.printStackTrace();
}
}
};
}
};
#Rule
public TestWatcher testWatcher2 = new TestWatcher() {
#Override
public Statement apply(Statement base, Description description) {
return new Statement() {
public void evaluate() throws Throwable {
try {
System.out.println("testWatcher2");
base.evaluate();
} catch (Throwable e) {
e.printStackTrace();
}
}
};
}
};
#Test
public void test() {
System.out.println("test");
}
}
Output:
testWatcher2
testWatcher1
test
Process finished with exit code 0
Upon further investigation:
Adding System.out.println(base.toString()); inside of each of those evaluate() calls lead to some really interesting output:
testWatcher2
com.glenpierce.Tests.base.SimpleTest$1$1#3c09711b
testWatcher1
org.junit.internal.runners.statements.InvokeMethod#5cc7c2a6
test
Process finished with exit code 0
It seems like each TestWatcher is looking at a different scope. Am I unintentionally nesting these things?

Rules in JUnit are designed so that they are linked to each other. base.evaluate() in one rule causes the next rule to run, until all the rules have run. Only if all the rules calls base.evaluate() then the test method is run.

Related

How to embed every test in a wrapper logic?

Given the requirement that every junit test have to run in the following wrapper:
#Test
public void testFooBar() {
SpecialLogic.runWith(new SpecialLogic("blah", "foo", ANYTHING), () -> {
// my test
});
}
I am trying to avoid adding SpecialLogic.runWith(...) for each test.
Is there any possibility by using #BeforeEach or any other way?
Otherwise, there is much of duplicated code:
#Test
public void testFooBar_2() {
SpecialLogic.runWith(new SpecialLogic("blah", "foo", ANYTHING), () -> {
// my test logic 2
});
}
#Test
public void testFooBar_3() {
SpecialLogic.runWith(new SpecialLogic("blah", "foo", ANYTHING), () -> {
// my test logic 3
});
}
There are two ways of doing this:
Write your custom Runner, all the tests will have to run with this runner.
This may be inappropriate if you already use another runner (say for spring or mockito)
Write your own Rule. The rule is a little bit newer way of doing what you've asked for,
and it doesn't "occupy" the slot of a runner which can be only one.
public final class SampleRule implements TestRule {
#Override public Statement apply(final Statement base,
final Description description) {
return new Statement() {
#Override public void evaluate() throws Throwable {
// do your stuff before actually running the test
try {
base.evaluate(); // This line actually runs the test.
} finally {
// do your stuff after running a test
}
}
};}}
Here is one of numerous guides for writing Rules:
Looks like you should implement your own TestRunner to wrap your custom logic around each test method call. There is an article over at Baelung explaining how this works.
#Before and #After? It won't use closures but should be functionally the same.
https://junit.org/junit4/javadoc/latest/org/junit/Before.html
https://junit.org/junit4/javadoc/latest/org/junit/After.html

How to mark #Test as failed in #AfterMethod

I am trying to find out a way if there is any way in TetstNG to mark a test method annotated with #Test as failed inside #AfterMethod.
#Test
public void sampleTest() {
// do some stuff
}
#AfterMethod
public void tearDown() {
// 1st operation
try {
// some operation
} catch(Exception e) {
// mark sampleTest as failed
}
// 2nd operation
try {
// perform some cleanup here
} catch (Exception e) {
// print something
}
}
I have some verification to be done in all tests, which I am doing under 1st try-catch block in tearDown(). If there is an exception in that block, mark the test as failed. Then proceed for next try-catch block.
I cannot reverse the order of try-catch blocks in tearDown() because, 1st block depends on 2nd.
To the best of my knowledge you cannot do it from within #AfterMethod configuration method, because the ITestResult object that gets passed to your configuration method [ Yes you can get access to the test method's result object by adding a parameter ITestResult result to your #AfterMethod annotated method ] is not used to update back the original test method's result.
But you can easily do this if you were to leverage the IHookable interface.
You can get more information on IHookable by referring to the official documentation here.
Here's an example that shows this in action.
import org.testng.IHookCallBack;
import org.testng.IHookable;
import org.testng.ITestResult;
import org.testng.annotations.Test;
public class TestClassSample implements IHookable {
#Test
public void testMethod1() {
System.err.println("testMethod1");
}
#Test
public void failMe() {
System.err.println("failMe");
}
#Override
public void run(IHookCallBack callBack, ITestResult result) {
callBack.runTestMethod(result);
if (result.getMethod().getMethodName().equalsIgnoreCase("failme")) {
result.setStatus(ITestResult.FAILURE);
result.setThrowable(new RuntimeException("Simulating a failure"));
}
}
}
Note: I am using TestNG 7.0.0-beta7 (latest released version as of today)

How do i control the order in which jUnit tests run [duplicate]

This question already has answers here:
How to run test methods in specific order in JUnit4?
(23 answers)
Closed 7 years ago.
I have this jUnit test class
public class TestRaavareBatch {
#Before
public void prep(){
try { new Connector(); }
catch (InstantiationException e) { e.printStackTrace(); }
catch (IllegalAccessException e) { e.printStackTrace(); }
catch (ClassNotFoundException e) { e.printStackTrace(); }
catch (SQLException e) { e.printStackTrace(); }
}
MySQLRaavareBatchDAO rvb = new MySQLRaavareBatchDAO();
#Test
public void testgetRaavareBatch() throws DALException{
RaavareBatchDTO rvbOBJ = rvb.getRaavareBatch(7);
assertEquals(7, rvbOBJ.getRaavareId());
assertEquals(100.0, rvbOBJ.getMaengde(),0.0);
assertEquals(7, rvbOBJ.getRbId());
}
#Test
public void testgetRaavareBatchList() throws DALException{
List<RaavareBatchDTO> rvbOBJ = rvb.getRaavareBatchList();
assertEquals(rvbOBJ.size(), 8);
}
#Test
public void testgetRaavareBatchListId() throws DALException{
List<RaavareBatchDTO> rvbOBJ = rvb.getRaavareBatchList(5);
assertEquals(rvbOBJ.size(), 2);
}
#Test
public void testcreateRaavareBatch() throws DALException{
RaavareBatchDTO test;
rvb.createRaavareBatch(test = new RaavareBatchDTO(8, 8, 200.0));
RaavareBatchDTO rvbOBJ = rvb.getRaavareBatch(8);
assertEquals(8, rvbOBJ.getRbId());
assertEquals(200.0, rvbOBJ.getMaengde(),0.0);
assertEquals(8, rvbOBJ.getRbId());
}
#Test
public void testupdateRaavareBatch() throws DALException{
RaavareBatchDTO test;
rvb.updateRaavareBatch(test = new RaavareBatchDTO(8, 7, 100.0));
RaavareBatchDTO rvbOBJ = rvb.getRaavareBatch(8);
assertEquals(7, rvbOBJ.getRaavareId());
assertEquals(100.0, rvbOBJ.getMaengde(),0.0);
}
}
It connects to a database with 7 rows, and after i run the last test "updateRaavareBatch" i have created a new row so the size of the list in testgetRaavareBatchList() will be 8. But it gives me an error because it counts the size before i create a new row..
How can i run testgetRaavareBatchList() after i create the new row and update it.
I once got something like that in testing queries, insertions and deletions in a database.
I ended with the following infra in order to ensure test independance :
prepare the database connection in a #Before method
rollback in #After
put some inserts in private not #Test annotated utility methods to avoid duplication
when needed the #Test methods called utility methods, and did their job with assertions
In another harder case, I created an embedded database in a #BeforeClass method and destroyed it in #AfterClass
But you should never rely on test order.
You can use #FixedMethodOrder annotation on your test class.
A simple example is the following:
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
//Running test cases in order of method names in ascending order
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class OrderedTestCasesExecution {
#Test
public void secondTest() {
System.out.println("Executing second test");
}
#Test
public void firstTest() {
System.out.println("Executing first test");
}
#Test
public void thirdTest() {
System.out.println("Executing third test");
}
}
Output:
Executing first test
Executing second test
Executing third test
Just one thing about your particular test scenario though. It is better in your case to have a proper #Before and #After methods to setup and rollback database tests. Later on, if your codebase is big enough you might run into cases where one test does not clean up properly and makes another random testcase fail.
References:
Simple TestCase source
JUnit Javadoc for the #FixMethodOrder
Another decent page on JUnit

JUnit MethodRule only tests one line

I've made an MethodRule and #Rule-annotation to make my test-life a bit easier.
It checks if a specific exception had been thrown and checks if the exception-message equals or contains the given message.
Now when i run a testmethod with more lines to test, it only takes the first line and than is ready. How do I make so all my lines in the testmethod are tested?
This is my code:
Annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
public #interface ExpectedDomeinValidatieMessage {
String value() default "";
String contains() default "";
}
MethodRule:
#Override
public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
ExpectedDomeinValidatieMessage message = method.getAnnotation(ExpectedDomeinValidatieMessage.class);
if (message == null) {
base.evaluate();
} else {
try {
base.evaluate();
Assert.fail("DomeinValidatieException not thrown");
} catch (DomeinValidatieException e) {
if (StringUtils.isNotBlank(message.value())) {
if (!e.getMessage().equals(message.value())) {
throwException(e, "", message.value(), e.getMessage());
}
}
if (StringUtils.isNotBlank(message.contains())) {
if (!e.getMessage().contains(message.contains())) {
throwException(e, "Segment niet gevonden:", message.contains(), e.getMessage());
}
}
}
}
}
private void throwException(Throwable exception, String message, String expected, String actual) {
ComparisonFailure cf = new ComparisonFailure(message, expected, actual);
cf.setStackTrace(exception.getStackTrace());
throw cf;
}
};
Usage:
#Test
#ExpectedDomeinValidatieMessage("[Werkzaamheden] WerkzaamMetGevaarlijkeStoffen niet gevuld")
public void valideerWerkzaamMetGevaarlijkeStoffen() throws DomeinValidatieException {
aanvraag.getVerzekerde().getWerkzaamheden().setWerkzaamMetGevaarlijkeStoffen(null);
validator.valideer();
}
If I use it like this, it only tests the first test in the method:
#Test
#ExpectedDomeinValidatieMessage("[Werkzaamheden] WerkzaamMetGevaarlijkeStoffen niet gevuld")
public void valideerWerkzaamMetGevaarlijkeStoffen() throws DomeinValidatieException {
aanvraag.getVerzekerde().getWerkzaamheden().setWerkzaamMetGevaarlijkeStoffen(null);
validator.valideer(); //Only this one is tested
aanvraag.getVerzekerde().getWerkzaamheden().setWerkzaamMetGevaarlijkeStoffen("bla");
validator.valideer(); //This is NOT tested
}
Run the code through a debugger. My guess is that the first call to valideer() does indeed throw an exception even though you don't expect it.
The JUnit assertXXX methods work by throwing exceptions (specifically AssertionError). So when an exception is thrown (either by your code, or by an assert) control exits from the test method. There isn't any way to restart from the place where the exception is thrown.
You probably want Parameterized, which allows you to run the same tests multiple times with different parameters.
EDIT: I suspect that valideer() is throwing an Exception. To explain a bit further, let's paraphrase your code. When you define a rule, what you're effectively doing is the following:
try {
base.evaluate(); // this calls valideerWerkzaamMetGevaarlijkeStoffen()
Assert.fail("DomeinValidatieException not thrown");
} catch (DomeinValidatieException e) {
// evaluate whether or not the test has failed or not
}
This means that if your first call to valideer() throws an Exception, then control is transferred to the catch block above. There isn't a chance to continue executing the test, because the control has passed elsewhere. You can pass/fail the test as much as you like, but control has passed to the catch block above.
By the way, MethodRule has been deprecated in the later versions, you should be using TestRule instead.

How to run tearDown type method for a specific test in JUnit class with multiple tests?

I have a junit testCase class with multiple test methods in it ( As requirement , we don't want to create separate class for each test.)
I wanna create a tearDown type method for EACH test method , which will run specifically for that test. Not for ALL test.
My problem is , in many tests i Insert record in database, test it and delete it after test.
But, If a test fails mid way , control don't reaches till end my dummy record ain't deleting.
I think only ONE tearDown() is allowed for one class, and this tearDown() don't know what object/record i created or inserted and what to delete!!!
I want to create a tearDown() or #After method just for one specific test. Something like finally{} in java for each method.
For Eg:
public class TestDummy extends TestCase {
public void testSample1(){
InsertSomeData1();
assertFalse(true);
runTearDown1();
}
public void testSample2(){
InsertSomeData2();
assertFalse(true);
runTearDown2();
}
public void runTearDown1(){
deleteDummyDatafromTestSample1....
}
public void runTearDown2(){
deleteDummyDatafromTestSample2....
}
}
Here control will never go to runTearDown1() or runTearDown2() and I don't a one common tearDown() because it won't know what data I inserted and thats specific to each method.
It seems your test relies on a fixed database, and future tests will break if your current test breaks. What I'd recommend is not to focus on this particular problem (a test-specific tearDown method that runs for each test), but your main problem - borken tests. Before your test run, it should always work with a clean database, and this should be the case for each test. Right now, your first test has a relationship with the second (through the database).
What the right approach would be is that you recreate your database before each test, or at the very least reset it to a basic state. In this case, you'll want a test like this:
public class TestDummy {
// this code runs (once) when this test class is run.
#BeforeClass
public void setupDatabase() {
// code that creates the database schema
}
// this code runs after all tests in this class are run.
#AfterClass
public void teardownDatabase() {
// code that deletes your database, leaving no trace whatsoever.
}
// This code runs before each test case. Use it to, for example, purge the
// database and fill it with default data.
#Before
public void before() {
}
// You can use this method to delete all test data inserted by a test method too.
#After
public void after() {
}
// now for the tests themselves, we should be able to assume the database will
// always be in the correct state, independent from the previous or next test cases.
#Test
public void TestSample2() {
insertSomeData();
assertTrue(someData, isValid());
}
}
Disclaimer: JUnit 4 tests (using annotations), might not be the right annotations, might not even be the right answer(s).
You could have smth like this:
interface DBTest {
void setUpDB();
void test();
void tearDownDB();
}
class DBTestRunner {
void runTest(DBTest test) throws Exception {
test.setUpDB();
try {
test.test();
} finally {
test.tearDownDB();
}
}
}
public void test48() throws Exception {
new DBTestRunner().runTest(new DBTest() {
public void setUpDB() {...}
public void test() {...}
public void tearDownDB() {...}
});
}
#iluxa . Gr8.. Your solution is perfect!!! In one test class i created two tests test48 and test49 (same as required in my code above testSample1 and testSample2) and viola! every test method now gets its own setup() and tearDown. Only this solution looks little complicated as need to use DBTestRunner in each method, but I don't see any better solution. I was thinking Junit may have some direct solution. like #After or tearDown() with some parameter or something.
Tks a lot.
Use MethodRule:
public class MyRule implements MethodRule {
#Override
public Statement apply(final Statement base, FrameworkMethod method, Object target) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
base.evaluate();
} catch (AssertionError e) {
doFail();
} finally {
doAnyway();
}
}
};
}
}
Then declare it in your test class:
public class TestDummy{
public MethodRule rule = new MyRule();
......
}

Categories