How can I link #BeforeEach with #Test method using JUnit extensions? - java

For example, we have 2 classes: BaseTest and Test; Test extends BaseTest.
BaseTest.class contains 2 methods with #BeforeEach annotations.
#BeforeEach
void setUp1() {}
#BeforeEach
void setUp2() {}
Test.class contains 2 methods with #Test annotations.
#Test
void test1() {}
#Test
void test2() {}
I want to link the #BeforeEach method with #Test method, so the setup1() would run only before test1() and the setup2() - only before test2().
I would appreciate a code sample of this task completed using JUnit extensions.

The operative word in #BeforeEach is each. These methods run before each test, and aren't really suitable for the usecase you're describing. If you need such a tight coupling, I'd suggest to move away from JUnit annotations, and just call the setup methods directly:
public class BaseTest {
void setUp1() {}
void setUp2() {}
}
public class Test extends BaseTest {
#Test
void test1() {
setUp1();
// test logic
}
#Test
void test2() {
setUp2();
// test logic
}
}

In Junit 5 you have a new feature called Nested tests that allows you to have nested classes each with it's own BeforeAll and AfterAll. This requires a little bit of change to your classes hierarchy BaseTest.class and Test.class but works like a charm :
#Nested Denotes that the annotated class is a non-static nested test
class. #BeforeAll and #AfterAll methods cannot be used directly in a
#Nested test class unless the "per-class" test instance lifecycle is
used. Such annotations are not inherited.

This is not possible like this. There are some other options you could consider:
Put setup2() and test2() in another test class. Since test1 and test2 do not share the setup ("fixture") they should be in separate classes anyway.
Remove the #BeforeEach annotation and call the setup methods explicitly at the start of the actual test methods.

You don't need to put test set up code only in #BeforeEach annotated methods. You can put it in the #Test method or (perhaps better) in a method called from the #Test method.

Related

How to test init function with #Postconstruct and map inside with junit mockito

I have a class to test but i dont know how to test it. Can somebody help for test?
#Component
public class KvkkCorrBankingExecuter {
private final Map<String, IKvkkCorrBankingExecuter> operationMap = new HashMap<>();
IKvkkCorrBankingExecuter executer;
#Autowired
DemandBoeExecuter demandBoeExecuter;
#Autowired
DemandCleanBaExecuter demandCleanBaExecuter;
#Autowired
DemandGuaranteeExecuter demandGuaranteeExecuter;
#Autowired
DemandLcExecuter demandLcExecuter;
#Autowired
DemandSlcExecuter demandSlcExecuter;
#PostConstruct
public void init() {
operationMap.put("DEMAND_BOE", demandBoeExecuter);
operationMap.put("DEMAND_CLEAN_BA", demandCleanBaExecuter);
operationMap.put("DEMAND_GUARANTEE", demandGuaranteeExecuter);
operationMap.put("DEMAND_LC", demandLcExecuter);
operationMap.put("DEMAND_SLC", demandSlcExecuter);
}
}
Map line and the init function are red highlighted in the covarage. They need to be tested.
I wont give a readymade answer, but some guidance. I would advice you to try it out, that is the only way to learn and remember.
How to write unit test for this class ?
The goal of the unit test would be to test all possible scenarios. The goal should not be just to make the code coverage report red, but to avoid any possible bugs in that code for various data conditions.
Since you are testing through jUnit, do following:
Create a test class - give class name such that it indicates what class is being tested. e.g. KvkkCorrBankingExecuterTest.java
Write a method with name that says what condition you are testing.
e.g. testInitFunction()
Since you are not using spring for test, the #Postconstruct annotated method won't be called automatically.
Because the test does not use spring, the autowired attributes will be null.
For that, create Mock variables with exact same definition as the class being tested.
Then do following:
Class KvkkCorrBankingExecuterTest{
//other mock variables similar to demandLcExecuter
#Mock
DemandLcExecuter demandLcExecuter;
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
#Test
public void testInitMethod(){
// 1. Create an instance of KvkkCorrBankingExecuter
// 2. Call init() method on that instance
// 3. Validate that the size of operationMap is 5
// 4. Validate that you get values corresponding to each key. The value will be // equal to the mock attributes in this class.
}
}
Other code suggestions:
Make attributes private.

What use is #TestInstance annotation in JUnit 5?

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.

How to use bean in static method which is called by #BeforeClass test method

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.

Exclude individual test from 'before' method in JUnit

All tests in my test class execute a 'before' method (annotated with JUnit's #Before) before the execution of each test.
I need a particular test not to execute this before method.
Is there a way to do it?
You can do this with a TestRule. You mark the test that you want to skip the before with an annotation of some description, and then, in the apply method in the TestRule, you can test for that annotation and do what you want, something like:
public Statement apply(final Statement base, final Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
if (description.getAnnotation(DontRunBefore.class) == null) {
// run the before method here
}
base.evaluate();
}
};
}
Consider using the #Enclosed runner to allow you to have two inner test classes. One with the required #Before method, the other without.
Enclosed
#RunWith(Enclosed.class)
public class Outer{
public static class Inner1{
#Before public void setup(){}
#Test public void test1(){}
}
public static class Inner2{
// include or not the setup
#Before public void setup2(){}
#Test public void test2(){}
}
}
Unfortunately you have to code this logic. JUnit does not have such feature.
Generally you have 2 solutions:
Just separate test case to 2 test cases: one that contains tests that require "before" running and second that contains tests that do not require this.
Implement your own test running and annotate your test to use it. Create your own annotation #RequiresBefore and mark tests that need this with this annotation. The test runner will parse the annotation and decide whether to run "before" method or not.
The second solution is clearer. The first is simpler. This is up to you to chose one of them.
This question has been asked a while ago, nevertheless, I would like to share my solution:
Annotate the desired method with #Tag("skipBeforeEach")
In your setup() method:
#BeforeEach
void setup(final TestInfo info) {
final Set<String> testTags = info.getTags();
if(testTags.stream()
.filter(tag->tag.equals("skipBeforeEach"))
.findFirst()
.isPresent()){
return;
}
// do your stuff
}```
I was looking for a solution to this problem and bumped into this question. As an update, in JUnit 5 this can be easily accomplished now with the use of the #Nested annotation.
If you are using Mockito, particularly Mockito 3.0, all stubbings will be "strict" and be validated by default.
You could use the Mockito lenient() method.
More here: https://www.baeldung.com/mockito-unnecessary-stubbing-exception#lenient-stubbing
One can also solve this by undoing what was done in #Before setup inside test case.
This is how it may look,
#Before
public void setup() {
TestDataSetupClass.setupTestData();
}
#Test
public void testServiceWithIgnoreCommonSetup() {
TestDataSetupClass.unSet();
//Perform Test
}
There will be pros and cons for solutions here. Minor con for this is, unnecessary cycle of setting and un-setting step. But goes well if one needs to do it for only a test case out of hundreds and avoid overhead of writing self AOP or maintaining multiple inner test classes.
If you have a #After method can clear the work done in #Before, you can manually call the #After method at the begining of your #Test method.

#After ,#before not working in testcase

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 {}

Categories

Resources