How to write JUnit test for switch case? - java

For example, method switchCase(). How do I write test code for it? I can just create 3 different tests just with different values for each test, respective to the switch case value, but I want to try a more efficient way of doing this.
#InjectMocks
private RepoFactory repoFactory;
public void switchCase() {
ConsentApplication consentApplication = repoFactory.getConsentApplicationRepo()
.findOne(consentApplicationVo.getId());
switch (CrestApiServiceNameEnum.getByCode(serviceNameEnum.getCode())) {
case CUST_DATA:
newCrestApiTrack.setRepRefNo(null);
httpHeaders.add("API-KEY", custDataApiKey);
break;
case CREDIT_PARAM:
httpHeaders.add("API-KEY", creditParamApiKey);
break;
case CONFIRM_MUL_ENT:
httpHeaders.add("API-KEY", multiEntitiApiKey);
break;
default:
LOGGER.info("Unexpected value: " + CrestApiServiceNameEnum.getByCode(serviceNameEnum.getCode()));
}
}
What I tried was, using #RunWith(JUnitParamsRunner.class), #ValueSource and #ParameterizedTest. However, this always produces NullPointerException at the first when and java.lang.Exception: Method testSwitchCase_SUCCESS should have no parameters. Can help me on this?
#ParameterizedTest
#ValueSource(strings = {"value1", "value2"})
void testSwitchCase_SUCCESS(String s) {
//have something
when(repoFactory.getConsentApplicationRepo().findOne(anyString()))
.thenReturn(consentApplication);
}

Annotate your test either with #Test or #ParameterizedTest but not both.
From the JUnit 5 documentation:
Parameterized tests make it possible to run a test multiple times with different arguments. They are declared just like regular #Test methods but use the #ParameterizedTest annotation instead.
Also the #RunWith annotation is from JUnit 4. When using JUnit 5 this annotation is unnecessary and should be removed.
Then, as Lesiak has commented: you should separate IO and logic. A method the receives the string to switch on as parameter and returns an object is much easier to test than a method that does everything: read data from the user, operates on it and produce some terminal output.
It seems that you have a mix of JUnit 4 and JUnit 5 annotations. That doesn't really work. If you want to use JUnit 5 then remove all uses of org.junit.Test and org.junit.runner.RunWith from your test class and replace them with org.junit.jupiter.api.Test and org.junit.jupiter.api.extension.ExtendWith.

Fortunately, I found a solution, the class should be annotated with #RunWith(JUnitParamsRunner.class) and #ExtendWith(MockitoExtension.class) and the in setup, we should put initMocks(this);. However, this will only mock a non-static class.
#Before
public void setup() {
initMocks(this);
setupRepos();
setupLoginUser();
setupUserLoginReturn();
setupLoggerAppender();
}

Related

Use parameterized test returns Method should have no parameters

I have a problem, I would like to pass the test method to send a request using the GET method and POST. I used parameterization, but I get information java.lang.Exception: Method simpleMessage should have no parameters
#Test
#ParameterizedTest
#ValueSource(strings = {"true", "false"})
public void simpleMessage (boolean isPost) {
verifyIdOdpEqual(isPost,1243, "message");
}
I don't quite understand what you trying to achieve as well but you have few problems with your code:
By presence of #ParameterizedTest and #ValueSource I assume you using JUnit 5. At the same time looks like you marked your method with annotation from JUnit 4 (because only in that case you will get an exception with the text you quoted).
#Test is redundant when the method is annotated with #ParametrizedTest.
You have 2 options how to fix all of the above:
If you want to use junit5 then you need to remove #Test annotation and make sure that your tests are launched by a runner that supports JUnit 5 (more info).
Example:
package test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class TestTest {
#ParameterizedTest
#ValueSource(booleans = {true, false})
public void test(boolean data) {
System.out.println(data);
}
}
If you want to use JUnit 4 then you need to remove #ParameterizedTest and #ValueSource annotations and rewrite your test to use parametrized runner (more info).
Simply remove the line #Test out of your code

Class-level test annotation in JUnit 5

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.

What is the equivalent of TestName rule in JUnit 5?

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();
}

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