JUnit 5 Before TestFactory Annotation - java

I've written a dynamic Test #TestFactory in JUnit5, now I've seen I can't do #Before for a dynamic Test, referring to
JUnit 5 User Guide - Writing Test Annotations.
Is there any workaround to do a #Before or similar to that before a TestFactory?
Method I want to put in an #Before since it's only initialization stuff:
public static void initialize() throws Exception{
buildTest = new XQueryTestHelper();
buildTest.initialization();
listTestSuiteIdentifier = buildTest.getListTestsuiteIdentifier();
arrayHdrInbPayTestcases = buildTest.getHdrInbPayTestcases();
arrayHeaderAndBodyTestcases = buildTest.getHeaderAndBodyTestcases();
listHeaderAndBodyTestSuites = buildTest.getHeaderAndBodyTestSuites();
listHdrInbPayTestSuites = buildTest.getHdrInbPayTestsuites();
}
Solution:
Using #BeforeAll / #AfterAll is possible in a dynamic Test. Referring to
Improve documentation of DynamicTest lifecycle
Dynamic Test Lifecycle
The execution lifecycle of a dynamic test is quite different than it is for a standard #Test case. Specifically, there are not any lifecycle callbacks for dynamic tests. This means that #BeforeEach and #AfterEach methods and their corresponding extension callbacks are not executed for dynamic tests. In other words, if you access fields from the test instance within a lambda expression for a dynamic test, those fields will not be reset by callback methods or extensions between the execution of dynamic tests generated by the same #TestFactory method.

Using #BeforeAll / #AfterAll is possible in a dynamic Test. Referring to
Improve documentation of DynamicTest lifecycle
Dynamic Test Lifecycle
The execution lifecycle of a dynamic test is quite different than it is for a standard #Test case. Specifically, there are not any lifecycle callbacks for dynamic tests. This means that #BeforeEach and #AfterEach methods and their corresponding extension callbacks are not executed for dynamic tests. In other words, if you access fields from the test instance within a lambda expression for a dynamic test, those fields will not be reset by callback methods or extensions between the execution of dynamic tests generated by the same #TestFactory method.

Using #BeforeAll or #AfterAll is not (yet) possible in a dynamic test.
There are efforts to implement this, but it seems that the developers have not yet decided on how it will be done.
I for myself have decided to manually invoke my setup method for the time being, which is pretty ugly.

Related

How to define priority in JUnit5

I have some unit test built with Junit in a Java project.
The only issue is that I want to define the order/priority of the tests.
I mean... I'm using #BeforeAll to execute first test, which is the login process and to get the access for the postlogin functionalities.
But right after that, I want to run another specific test.
And then the rest...
I checked and there is an option to use #Order() annotation, but my idea is not to be ordering every test like this... I just wanna run first the login, and then a test that I need to run all the others. So after the first two test, the others doesn't matter in which order they are.
First, having unit tests depend on other unit tests is typically bad design. The JUnit 5 User Guide mentions this:
Although true unit tests typically should not rely on the order in which they are executed, there are times when it is necessary to enforce a specific test method execution order — for example, when writing integration tests or functional tests where the sequence of the tests is important, especially in conjunction with #TestInstance(Lifecycle.PER_CLASS).
Consider if what you're doing is testing or set-up. If the action of logging in is just set-up for your tests then you should do this in a method annotated with #BeforeAll or #BeforeEach, whichever makes more sense in your context. Afterwards, you may need to clean-up using #AfterAll or #AfterEach, depending on which "before annotation" you used.
If you're actually trying to test the login code then try to separate these tests from the others. You could do this by moving them into a separate class file or even leveraging #Nested classes (if appropriate). Instead of having your later tests require a real login you should use a fake login. In other words, mock the dependencies needed for the later tests. This will remove the inter-test dependency situation. And don't be afraid to re-"login" for each test (e.g. by using #BeforeEach); if you're using mocks this shouldn't be too expensive.
Note: As of JUnit 5.4 you might even be able to abort some tests if previous tests fail using a TestWatcher extension, as mentioned in this Q&A. However, using such an approach seems better suited for integration tests rather than unit tests.
That said, what you want should be possible. You mention #Order but then say you're hesitant to use it because you don't want to order every method, only make sure that two tests run before all the others. You don't have to add the annotation to every method. If you look at the documentation of MethodOrderer.OrderAnnotation, you'll see:
MethodOrderer that sorts methods based on the #Order annotation.
Any methods that are assigned the same order value will be sorted arbitrarily adjacent to each other.
Any methods not annotated with #Order will be assigned a default order value of Integer.MAX_VALUE which will effectively cause them to appear at the end of the sorted list.
And from Order.value():
Elements are ordered based on priority where a lower value has greater priority than a higher value. For example, Integer.MAX_VALUE has the lowest priority.
This means you only need to annotate your two tests with #Order and leave the rest alone. All the test methods without the #Order annotation will run in any order, but after the first two tests.
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class MyTests {
#Test
#Order(1)
void firstTest() {}
#Test
#Order(2)
void secondTest() {}
#Test
void testFoo() {}
#Test
void testBar() {}
// other tests...
}

If #before executes after constructor, how do you initialize the class?

I am preparing some JUnit tests in Oracle ADF and I am getting surprised because I am seeing that constructor of the tested class is executed before the #before setup() method...
The issue is the constructor needs initialized variables that I was setting to constructor from the setup method... And logically I always get a beautiful NullPointerException...
The only solution I can see is initialize variables directly from the constructor, but I see that very ugly
Any idea? Thanks in advance guys
Maybe you can use JUnit's #BeforeClass annotation.
Sometimes several tests need to share computationally expensive setup (like logging into a database). While this can compromise the independence of tests, sometimes it is a necessary optimization. Annotating a public static void no-arg method with #BeforeClass causes it to be run once before any of the test methods in the class. The #BeforeClass methods of superclasses will be run before those the current class.
#Before:
When writing tests, it is common to find that several tests need similar objects created before they can run. Annotating a public void method with #Before causes that method to be run before the Test method. The #Before methods of superclasses will be run before those of the current class.
#BeforeClass will be executed before constructor call; the sequence is
#BeforeClass
Construcor call
#Before
#Test

Cleanup after all JUnit test runs

In my project I have to do some repository setup before all tests and after successful tests I want to clean up, I know #afterClass is used for this but it requires static variables but i dont want to make my objects statics, so is there any other way by which I can achieve this??
If you're using JUnit4, then use #After. Documentation here. Note that your methods annotated this way will be executed after each test case, in a similar fashion to #Before being executed before each test case.
If you're writing an integration test with multiple test cases and your setup is heavy, you could use a combination of #BeforeClass to set up static objects and #After to mutate/clean up/reset certain parts of these objects' states. This, of course, would violate your requirement of not using static variables, but I can't really see the rationale behind that requirement. Recall that JUnit instantiates the test class once for every single test case.
If you want set up and tear down before and after each test method, use #Before and #After. If you want to set up once, run all your tests and then tear down, use #BeforeClass and #AfterClass.
Yes, #BeforeClass and #AfterClass are static methods, but note that JUnit recreates your test class instance for each test method, so you cannot maintain any information in non-static fields of a test class across different tests.
I, as the other commenters here, have a feeling that you want to avoid static fields because there's a common opinion that they are bad practice. Please note, however, that good practice in writing code often does not apply to good practice in writing tests. This is one such example.

TestNG - #BeforeMethod for specific methods

I'm using Spring Test with TestNG to test our DAOs, and I wanted to run a specific text fixture script before certain methods, allowing the modifications to be rolled back after every method so that the tests are free to do anything with the fixture data.
Initially I thought that 'groups' would be fit for it, but I already realized they're not intended for that (see this question: TestNG BeforeMethod with groups ).
Is there any way to configure a #BeforeMethod method to run only before specific #Tests? The only ways I see are workarounds:
Define an ordinary setup method and call at the beginning of every #Test method;
Move the #BeforeMethod method to a new class (top level or inner class), along with all methods that depend on it.
Neither is ideal, I'd like to keep my tests naturally grouped and clean, not split due to lack of alternatives.
You could add a parameter your #BeforeMethod with the type 'java.lang.reflect.Method'. TestNG will then inject the reflection information for the current test method including the method name, which you could use for switching.
If you add another 'Object' parameter, you will also get the invocation parameters of the test method.
You'all find all on possible parameters for TestNG-annotated methods in chapter 5.18.1 of the TestNG documentation.
Tests are simply not designed to do this. Technically speaking, a single tests is supposed to handle being idempotent for itself meaning it sets up, tests, and takes down. That is a single test. However, a lot of tests sometimes have the same set-up and take down method, whereas other tests need one set-up before they all run. This is the purpose of the #Before type tags.
If you don't like set-up and tear-down inside your test, your more then welcome to architect your own system, but technically speaking, if certain methods require specific set-ups or tear-downs, then that really should be embodied IN the test, since it is a requirement for test to pass. It is ok to call a set-up method, but ultimately, it should be OBVIOUS that a test needs a specific set-up in order to pass. After all, if your using specific set-ups, aren’t you actually testing states rather than code?

Test invocation: how to do set up common to all test suites

Is there a way to know in a JUnit 4 test Class, if the Class was initiated by a Test-Suite ?
I have global things that I want to run before all tests (regarding in-memory DB), so I thought doing it in the test-suit. However, I still want to be able to initiate one test at a time without a Test-Suit, So I need to know if I need to initialize the global things in the #Before part of the test... Does any-one know if it's possible ?
There are several ways to achieve this. The easiest and simplest is to have a 'test' which is run at the beginning and end of your suite which set up your database and then set a global flag. In your #Before and #After tests you check this flag and if necessary do the setup/teardown.
#RunWith(Suite.class)
#SuiteClasses({SetupTest.class, RealTest.class, TeardownTest.class});
This is the simplest solution, but it isn't very nice, so a neater solution would be to use a TestRule. Look at extending ExternalResource. This implements before & after logic which surrounds your test methods. This would allow you to factor out your #Before and #After methods, to reuse the same code everywhere.
Then, for your suite, you need to implement before/after logic as well. Unfortunately, the class annotated with #RunWith(Suite.class) isn't actually instantiated, so you can't use the constructor of that class, but you can extend Suite. Depending upon how you will run this, you will will need to implement one of the constructors, using #RunWith as an example:
public class MySuite extends Suite {
/**
* Called reflectively on classes annotated with <code>#RunWith(Suite.class)</code>
*
* #param klass the root class
* #param builder builds runners for classes in the suite
* #throws InitializationError
*/
public MySuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
this(builder, klass, getAnnotatedClasses(klass));
// put your global setup here
// set global variable
}
}
Then run your test suite with
#RunWith(MySuite.class)
There are several constructors which are used in different situations, look at the comments next to each for specifics. You still need to use a global variable so that your Rules don't re-execute the setup code. The above will work if you're wanting to execute only setup code, executing teardown code is harder, but can be done. Let me know if you need it :-)
If you're wanting more flexibility (say executing setup code only for specific methods), then see my answer to How to define JUnit method rule in a suite?.
I would use JUnit's #BeforeClass and #AfterClass annotations to indicate methods to do this type of work.
From the #BeforeClass Javadoc:
Sometimes several tests need to share computationally expensive setup
(like logging into a database). While this can compromise the
independence of tests, sometimes it is a necessary optimization.
Annotating a public static void no-arg method with #BeforeClass causes
it to be run once before any of the test methods in the class. The
#BeforeClass methods of superclasses will be run before those the
current class.
You could place some #BeforeClass code in each test suite, which delegates to an auxiliary class that does the common set up. The auxiliary class could have a static boolean that records whether the set up has already been done. If it has already been done, the auxiliary class would do nothing.

Categories

Resources