Can you give a simple explanation of #TestInstance annotation and how it is useful in JUnit 5?
I think we can achieve the same effect probably by making our fields static.
I think the docs provide a useful summary:
If you would prefer that JUnit Jupiter execute all test methods on the same test instance, simply annotate your test class with #TestInstance(Lifecycle.PER_CLASS). When using this mode, a new test instance will be created once per test class. Thus, if your test methods rely on state stored in instance variables, you may need to reset that state in #BeforeEach or #AfterEach methods.
The "per-class" mode has some additional benefits over the default "per-method" mode. Specifically, with the "per-class" mode it becomes possible to declare #BeforeAll and #AfterAll on non-static methods as well as on interface default methods. The "per-class" mode therefore also makes it possible to use #BeforeAll and #AfterAll methods in #Nested test classes.
But you've probably read that already and you are correct in thinking that making a field static will have the same effect as declaring the field as an instance variable and using #TestInstance(Lifecycle.PER_CLASS).
So, perhaps the answer to the question "how it could be useful in JUnit 5" is that using a #TestInstance ...
Is explicit about your intentions. It could be assumed that use of the static keyword was accidental whereas use of #TestInstance is less likely to be accidental or a result of thoughless copy-n-paste.
Delegates the responsibility for managing scope and lifecycle and clean up to the framework rather than having to remember to manage that yourself.
This annotation was introduced to reduce the number of objects created when running your unit tests.
Adding #TestInstance(TestInstance.Lifecycle.PER_CLASS) to your test class will avoid that a new instance of your class is created for every test in the class.
This is particulary usefull when you have a lot of tests in the same test class and the instantiation of this class is expensive.
This annotation should be used with caution. All unit tests should be isolated and independent of eachother. If one of the tests changes the state od the test class then you should not use this feature.
Making your fields static to achieve the same effect is not a good idea. It will indeed reduce the number of objects created but they cannot be cleaned up when all tests in the test class are executed. This can cause problems when you have a giant test suite.
#TestInstance is used to configure the lifecycle of test instances for the annotated test class or test interface:
PER_CLASS: A new test instance will be created once per test class.
PER_METHOD: A new test instance will be created for each test method, test factory method, or test template method. This mode is analogous to the behavior found in JUnit versions 1 through 4.
If #TestInstance is not explicitly declared on a test class or on a test interface implemented by a test class, the lifecycle mode will implicitly default to PER_METHOD.
Setting the test instance lifecycle mode to PER_CLASS enables the following features:
Shared test instance state between test methods in a given test class as well as between non-static #BeforeAll and #AfterAll methods in the test class.
Declaration of #BeforeAll and #AfterAll methods in #Nested test classes.
Declaration of #BeforeAll and #AfterAll on interface default methods.
Simplified declaration of #BeforeAll and #AfterAll methods in test classes implemented with the Kotlin programming language.
See the test instance lifecycle documentation for further details.
since no one provide a proper coding example, I would like to give a simple code sample as below to understand the concept,
Per Method Sample - Default Option in Junit5
Note two methods are static, otherwise it will fire an exception because class instantiate in each method.
#TestInstance(Lifecycle.PER_METHOD)
public class MathUtilTestPerMethod {
MathUtil util;
#BeforeAll
static void beforeAllInit() {
System.out.println("running before all");
}
#AfterAll
static void afterAllCleanUp() {
System.out.println("running after all");
}
#BeforeEach
void init() {
util = new MathUtil();
System.out.println("running before each...");
}
#AfterEach
void cleanUp() {
System.out.println("running after each...");
}
#Test
void testSum() {
assertEquals(2, util.addtwoNumbers(1, 1));
}
}
Per Class Sample
Note that static is removed from the two methods and MathUtil object is created globally not in a method, because class instantiate only once.
#TestInstance(Lifecycle.PER_CLASS)
public class MathUtilTestPerClass {
MathUtil util = new MathUtil();
#BeforeAll
void beforeAllInit() {
System.out.println("running before all");
}
#AfterAll
void afterAllCleanUp() {
System.out.println("running after all");
}
#BeforeEach
void init() {
System.out.println("running before each...");
}
#AfterEach
void cleanUp() {
System.out.println("running after each...");
}
#Test
void testSum() {
assertEquals(2, util.addtwoNumbers(1, 1));
}
}
This is also useful when writing tests in Kotlin (because it doesn't have static methods).
So, instead of using a companion object with #JvmStatic funs in it for #BeforeAll or #AfterAll, make the lifecycle PER_CLASS and annotate regular methods with #BeforeAll or #AfterAll:
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTest {
#BeforeAll
fun setup() {
println("I am invoked only once")
}
}
When using this approach, be careful to reset your instance variables in #BeforeEach or #AfterEach funs if necessary.
Thanks to this article for its help.
Related
TestNG has a nice feature whereby the #Test annotation is added to the test class (instead of the test method). When the class is annotated, all public void-returning methods on the class are treated as test methods, as per the documentation.
#Test
public class Test1 {
public void test1() {
}
public void test2() {
}
}
Does JUnit 5 support a similar concept?
If not, is there an extension that would allow Junit 5 to be extended?
(I can't find any discussion of class-level annotations wrt JUnit 5, maybe I've missed it. Having to annotate each method is error-prone, with a high chance of forgetting to annotate a method, and thus having the tests not run, creating a false sense of confidence.)
Update: Now raised as an issue.
No, this isn't available in JUnit 5.
For a time in JUnit 3, you could extend the TestCase class and then all of your methods which were prefixed with test* would be run automatically, but not only was that more subject to breakage, it's actually actively deprecated and modern frameworks won't run with those older-style tests.
How can I get name of the test method in JUnit 5?
Declare a parameter of type TestInfo in your test method and JUnit will automatically supply an instance of that for the method:
#Test
void getTestInfo(TestInfo testInfo) { // Automatically injected
System.out.println(testInfo.getDisplayName());
System.out.println(testInfo.getTestMethod());
System.out.println(testInfo.getTestClass());
System.out.println(testInfo.getTags());
}
You can get test method name (and more) from the TestInfo instance as shown above.
In addition to what is written about injecting TestInfo to test method it is also possible to inject TestInfo to methods annotated with #BeforeEach and #AfterEach which might be useful sometimes:
#BeforeEach
void setUp(TestInfo testInfo) {
log.info(String.format("test started: %s", testInfo.getDisplayName());
}
#AfterEach
void tearDown(TestInfo testInfo) {
log.info(String.format("test finished: %s", testInfo.getDisplayName());
}
An alternative for having the test name globally available as was possible in JUnit 4 is to shim the functionality yourself in a setup method using the TestInfo interface.
From the JUnit documentation on "Dependency Injection for Constructors and Methods":
The TestInfo can then be used to retrieve information about the current container or test such as the display name, the test class, the test method, and associated tags.
Here we leverage the fact that the built-in resolvers will supply an instance of TestInfo corresponding to the current container or test as the value for parameters of type TestInfo to methods annotated as lifecycle hooks (here we use #BeforeEach).
import org.junit.jupiter.api.TestInfo;
public class MyTestClass {
String displayName;
#BeforeEach
void setUp(TestInfo testInfo) {
displayName = testInfo.getDisplayName();
// ... the rest of your setup
}
}
This for example enables you to reference the current test name in other non-test methods (such as various utility methods) without having to include the test name as a parameter to each function call from the initial test method to that utility method.
You can do the same for other information about the current container or test.
Seems like the only disadvantages are:
the instance variable cannot be made final, as it is set dynamically
may pollute your setup code
For reference, here is how the TestName-Rule might be implemented in JUnit 4:
public class MyTestClass {
#Rule
public final TestName name = new TestName();
}
Let's suppose I have a test class A which extends from class B. This class A has one method with #BeforeClass annotation:
#BeforeClass
public static void setUp(){
createFakeData();
}
The method createFakeData() is in class B and its function is to create an object in database.
In order to do that, I have a bean in class B:
#Autowired
private DummyObjectsFactory dummyObjectsFactory;
And the content of the method createFakeData() could be something like that which returns a FakeData object:
public FakeData createFakeData() throws Exception
{
return dummyObjectsFactory.createFakeData();
}
The problem I'm facing is that the #BeforeClass method has to be static, that means that the createFakeData method has to be static too. But I cannot set that method to static because my bean dummyObjectsFactory will be always null.
How can I make my createFakeData method static avoiding my dummyObjectsFactory bean to be not null?
As far as I know, that is not permitted in JUnit. However you can do some things for arrange it.
First, you can use TestNG, which allows to do exactly what you want.
If that is not an option, instead of using #BefloreClass annotation, you can use #Before. The difference between both is that #BeforeClass executes the method before all the tests while #Before executes the method before each test. If you use #Before, I would annotate the class with #Transactional in order to delete the data saved in the database.
In the end, if you don't want to execute the method for each test, you can use #Before and flat the call:
#Before
public void init(){
if(!fakeDataCalled){
createFakeData();
fakeDataCalled=true;
}
}
I believe you want to annotate your test class (B) with #RunWith(SpringRunner.class) so that the autowiring happens correctly.
Take a look at section 15.4.4 in the Spring Reference.
You can also just browse to that page and search for "RunWith"
Caveats:
I don't like static methods. They tend to make unit testing difficult.
I don't like extending tests to make other tests. I find it easier to make each test standalone and use composition for any shared functionality (i.e. make utility classes for shared test functionality that reside in the test source tree).
I don't like my unit tests depending on autowiring. I mock all the dependencies and inject them with either reflection or the #InjectMocks annotation.
Assume that interface for is defined
interface Foo {
int getBaz();
void doBar();
}
Further assume that the contract states that everytime doBar is called baz is incremented. (Ok this is a contrived bit of code but stick with me here)
Now I want to provide a unit test that I can provide to Foo implementers so that they can verify that they meet all the contract conditions.
class FooTest {
protected Foo fooImpl;
#Test
public void int testBazIncrement()
{
int b = fooImpl getBaz();
fooImpl.doBar();
Assert.assertEquals( b+1, fooImpl.getBaz();
}
}
What are the best practices for making the test available to the implemnters of Foo? It seems to me that there needs to be a mechanism for them to call the FooTest and provide a Foo or a FooFactory to construct Foo instances. Furthermore, if there are many tests (think big interface) then I want to put all those tests in one FooTest class.
Are there any best practices for how to implement such tests?
This is a textbook example of Dependency Injection. If you use Spring as the DI container, you can wire in the fooImpl
#Inject
protected Foo fooImpl;
Your test needs to be annotated with #RunWith(SpringJUnit4ClassRunner.class), and it's up to the interface provider to configure Spring with their implementation.
Without a DI container, you can just create an abstract test class with all the tests in it and an abstract method to provide the implementation object.
protected abstract Foo createFoo();
It's up to the implementation provider to subclass the test and implement the abstract method.
class FooImplTest extends FooTestSuper {
#Override
protected Foo createFoo() {
return new FooImpl();
}
If you have multiple tests, consider JUnit's #Suite annotation. It's compatible with the Spring test runner.
You can implement a testDataFactory where you istance your objects, or use GSon for create your objects (personally, I like GSon, is clear and fast, you learn it in a few time).
For the test implementation, I suggest to write more tests and not a single one.
In this way, unit test can be indipendent and you can segregate your problems in a closed structure.
Sonar
Sonar is a tool that help you a lot, making analisys of your code. You can see from sonar front-end how you application is tested:
sonar unit test
as you can see, Sonar can show you where your code is tested or not
Why not just have, say, a InterfaceTester that gets called from the unit tests InterfaceImplATest, InterfaceImplBTest, etc?
e.g.
#Test
public void testSerialisation()
{
MyObject a = new MyObject();
...
serialisationTester.testSimpleRoundTrip(a);
serialisationTester.testEdgeCases(a);
...
}
After much pondering and some dead-ends I have begun using the following pattern:
In the following:
[INTERFACE] refers to the interface being tested.
[CLASS] refers to the implementation of the interface being tested.
Interface tests are built so that developers may test that implementations meet the contract
set out in the interface and accompanying documentation.
The major items under test use an instance of an [INTERFACE]ProducerInterface to create the instance of the object being tested. An implementation of [INTERFACE]ProducerInterface must track all the instances created during the test and close all of them when requested. There is an Abstract[INTERFACE]Producer that handles most of that functionality but requires a createNewINTERFACE implementation.
TESTS
Interface tests are noted as Abstract[INTERFACE]Test. Tests generally extend the Abstract[INTERFACE]ProducerUser class. This class handles cleaning up all the graphs at the end of the tests and provides a hook for implementers to plug in their [INTERFACE]ProducerInterface implementation.
In general to implement a test requires a few lines of code as is noted in the example below
where the new Foo graph implementation is being tested.
public class FooGraphTest extends AbstractGraphTest {
// the graph producer to use while running
GraphProducerInterface graphProducer = new FooGraphTest.GraphProducer();
#Override
protected GraphProducerInterface getGraphProducer() {
return graphProducer;
}
// the implementation of the graph producer.
public static class GraphProducer extends AbstractGraphProducer {
#Override
protected Graph createNewGraph() {
return new FooGraph();
}
}
}
SUITES
Test suites are named as Abstract[INTERFACE]Suite. Suites contain several tests that excersize all of the tests for components of the object under test. For example if the Foo.getBar() returned an instance of the Bar interface the Foo suite includes tests for the Foo iteself as well as running the Bar tests the Bar. Running the suites is a bit more complicated then running the tests.
Suites are created using the JUnit 4 #RunWith(Suite.class) and #Suite.SuiteClasses({ })
annotations. This has several effects that the developer should know about:
The suite class does not get instantiated during the run.
The test class names must be known at coding time (not run time) as they are listed in the annotation.
Configuration of the tests has to occur during the static initialization phase of class loading.
To meet these requirements the Abstract[INTERFACE]Suite has a static variable that holds the instance of the [INTERFACE]ProducerInterface and a number of local static implementations of the Abstract tests that implement the "get[INTERFACE]Producer()" method by returning the static instance. The names of the local tests are then used in the #Suite.SuiteClasses annotation. This makes creating an instance of the Abstract[INTERFACE]Suite for an [INTERFACE] implementation fairly simple as is noted below.
public class FooGraphSuite extends AbstractGraphSuite {
#BeforeClass
public static void beforeClass() {
setGraphProducer(new GraphProducer());
}
public static class GraphProducer extends AbstractGraphProducer {
#Override
protected Graph createNewGraph() {
return new FooGraph();
}
}
}
Note that the beforeClass() method is annotated with #BeforeClass. the #BeforeClass causes it to be run once before any of the test methods in the class. This will set the static
instance of the graph producer before the suite is run so that it is provided to the enclosed tests.
FUTURE
I expect that further simplification and removal duplicate code can be achieved through the use of java generics, but I have not gotten to that point yet.
Here are some of my thoughts about how to make a qualified unit test:
First of all, try to make your a implementer class fully tested, which means all of its methods should be covered by the UT. Doing this will save you a lot of time when you need to refactor your code. For your case, it could be :
class FooTest {
protected Foo fooImpl;
#Test
public void testGetBaz() {
...
}
#Test
public void testDoBar() {
...
}
}
You will find you need to check the internal state of your class and there is nothing wrong it for UT should be a kind of white-box test.
Second, all methods should be tested separately and not depend on each other. In my opinion, for your code posted above, it looks like more than a function test or an integration test, but it's also necessary.
Third, I don't think it's a good practice to use spring or other container to assemble the target object for you, which will make your test running relatively slow, especially when there a load of tests to run. And your class should intrinsically be pojo and you can complete the assembling in another method in your test class if your target object is really complex.
Fourth, if the parent interface of some class is really big, Dividing the test methods into several groups is something you should do. Here is more info.
I have started testing and now i want to use #After, #Before and #Test but my application only runs the #Before method and gives output on console
before
However, if I remove #After and #Before it runs the #Test. My code is here:
public class TestPractise extends AbstractTransactionalDataSourceSpringContextTests{
#Before
public void runBare(){
System.out.println("before");
}
#Test
public void testingMethod(){
System.out.println("testing");
}
#After
public void setDirty(){
System.out.println("after");
}
}
Why aren't #After, #Test and #before working simultaneously?
Use #BeforeEach instead of #Before and #AfterEach instead of #After.
The AbstractTransactionalDataSourceSpringContextTests class forces the use of the old JUnit 3.x syntax, which means that any of the JUnit 4 annotation will not work.
Your method runBare() is executed not because of the #Before annotation, but because it is named runBare(), which is a method provided by ConditionalTestCase and JUnit TestCase class.
So you have 2 solutions:
Use the AlexR answer to use JUnit 4 tests and Spring;
Keep your inheritance of AbstractTransactionalDataSourceSpringContextTests, but use the onSetUp and onTearDown methods instead of the #Before and #After methods.
Check that you are using Junit4 because from Junit5 onwards #Before/#After is now #BeforeEach/#AfterEach and similalry #BeforeClass/#AfterClass is #AfterAll/#BeforeAll.
It should work... But since you are working with spring framework and JUnit 4 was introduced years ago I's suggest you to use annotations instead of inheritance.
So, annotate you class with #RunWith(SpringJUnit4ClassRunner.class). Remove extends AbstractTransactionalDataSourceSpringContextTests.
Don't forget to make the #Before and #After methods static
Now it should work.
Even if you want to extend Spring abstract test classes at least pay attention that some of them are deprecated. For example class AbstractTransactionalDataSourceSpringContextTests is deprecated.
JUnit Jupiter, aka "JUnit 5": use #BeforeAll
If you use the newer JUnit Jupiter (Java 8 onward), you'll want to replace #Before with #BeforeAll.
Furthermore, you'll need to either annotate your test class with #TestInstance(Lifecycle.PER_CLASS) or make the #BeforeAll method static. Here's an example:
#TestInstance(Lifecycle.PER_CLASS)
class MyTestClass {
MyHeavyResource sharedResource;
#BeforeAll
void init() {
System.out.println("init");
sharedResource = new MyHeavyResource(1234);
}
#Test
void myTest() {
System.out.println("myTest");
sharedResource.methodUnderTest();
}
}
Understanding Lifecycle.PER_CLASS
The likely reason JUnit 5 is more stringent with this -- demanding either static or Lifecycle.PER_CLASS -- is that it wants the test author to acknowledge that any resource instance initialized in a #BeforeAll method will genuinely be shared across each individual unit test method within the class. This could compromise their isolation, for example if the sharedResource in the above example isn't stateless/idempotent.
If sharedResource cannot be safely shared (or if it's reasonably leightweight), the init method should be annotated with #BeforeEach instead, which would create a new instance before executing each individual test within the class.
The Javadoc for TestInstance explain how using Lifecycle.PER_CLASS actually enforces a single instance of the test class; whereas the behaviour of JUnit 4 and earlier was equivalent to Lifecycle.PER_METHOD, which created a new instance of the test class for each #Test method contained therein. This would somewhat mislead the author to suppose that #Before was only executed once for each of those tests.
If you use auto import in an IDE, make sure the #Test and #Before are imported from the org.junit package.
in my case, I had that problem the solution was to change the java access modifier, It was way private.
before (not working)
#Test
void validate() throws Exception {}
after (working)
#Test
public void validate() throws Exception {}