JUnit 5, pass information from test class to extension - java

I am trying to write an extension for Junit5 similar to what I had for Junit4 but I am failing to grasp how to do that in the new (stateless) extension system.
The idea in the previous version was that user could pass information into extension class and hence change the way it behaved. Here is a pseudo snippet showing approximately what is used to do:
public void MyTest {
// here I can define different behaviour for my extension
#Rule MyCustomRule rule = MyCustomRule.of(Foo.class).withPackage(Bar.class.getPackage).alsoUse(Cookies.class);
#Test
public void someTest() {
// some test code already affected by the #Rule
// plus, user has access to that class and can use it, say, retrieve additional information
rule.grabInfoAboutStuff();
}
}
Now, I know how to operate JUnit 5 extension, what lifecycles to use etc. But I don't know how to give the test-writer the power to modify my extension's behaviour with JUnit5. Any pointers appreciated.

As of JUnit Jupiter 5.0.1, it is unfortunately not possible to pass parameters to an Extension programmatically like you could for rules in JUnit 4.
However, I am working on adding such support in JUnit Jupiter 5.1. You can follow the following issue if you like: https://github.com/junit-team/junit5/issues/497
In the interim, the only way to pass information to an extension is for the extension to support custom annotations and extract the user-supplied information from there. For example, I allow users to provide a custom SpEL expression in the #EnabledIf annotation in the Spring Framework, and my ExecutionCondition extension pulls the expression from the annotation using reflection.

followup on the (accepted) answer from Sam as in the meantime the referred bug has been implemented with junit 5.1
use #RegisterExtension
see https://junit.org/junit5/docs/current/user-guide/#extensions-registration-programmatic

Related

Testing conditions and exceptions in Integration Tests?

I have written several Unit Tests and now switched to write Integration Test in our Java (Spring Boot) app. We use JUnit and Mockito libraries for testing.
As far as I know, Integration Tests check the entire rings rather than a function. However, I am confused that if I should also check the if conditions in the methods while integration testing. Here is an example service method:
#Override
public CountryDTO create(CountryRequest request) {
if (countryRepository.existsByCodeIgnoreCase(countryCode)) {
throw new EntityAlreadyExistsException();
}
final Country country = new Country();
country.setCode("UK");
country.setName("United Kingdom");
final Country created = countryRepository.save(country);
return new CountryDTO(created);
}
My questions are:
1. Can I write integration test for a Service or a Repository class?
2. when I test create method in my service above, I think I just create the proper request values (CountryRequest) in my Test class, then pass them to this create method and then check the returned value. Is that true? Or do I also need to test the condition in the if clause (countryRepository.existsByCodeIgnoreCase(countryCode))?
3. When I test find methods, I think I should first create record by calling create method and the proper place for this is #BeforeEach setup() {} method. Is that true?
If you wrote Unit tests that made sure, your services and repositories are working correctly (for example by validation and parameterized tests) I believe, you don't have to write integration tests for them.
You should write integration tests to check the behavior of your app. By testing if your controller is working correctly you will also check if service and repo are ok.
I believe unit test should check it.
Do you ask if you should create record in db? If you want to test if repository is correctly communicating with service and it with controller, you have to do it with some data.

Can I mock Kotlin service into java Junit test

I'm currently writing Junit test with Mockito in java. But one microservice is written in Kotlin.
I try to mock the kotlin service, but it doesn't work as I excepted.
I plan to return a customize response inside the test, I checked it with debugger, instead of returning the response, it always runs into the kotlin function(getFile).
#Mock
private FileService fileservice; // this service written in Kotlin
#Before
public void setUp() {
Response respone = new Response(...);
when(fileservice.getFile(any())).thenReturn(response);
}
The best approach is to use mocking library designed for Kotlin, there is few options for this:
If still needed to stick to mockito, there is official mockito support for kotlin, more details here: https://github.com/mockito/mockito-kotlin
Also there is mockk library that specially designed for kotlin, and it better fits than mockito: https://mockk.io/
Also many java libraries using byte-code generated proxies like mockito does, while kotlin makes every class final by default, there is a kotlin plugin named all-open, which can make all needed classes open: https://kotlinlang.org/docs/all-open-plugin.html

Is there any way in JUnit > 5.6.0 to load context before class execution condition evaluation?

My goal is to execute tests in test class only when some spring property declared in application-foo.properties is equal to some constant.
I've tried to reach this by writing my own ExecutionCondition with annotation using it, and when I use it on #Test method it works fine. But using one on a test class leads to the problem: condition evaluates before Spring's context is up.
According to the docs:
If an ExecutionCondition disables a test method, that does not prevent
the test class from being instantiated.
But what should I do if I want to?
Script-based condition APIs and their supporting implementations are
deprecated with the intent to remove them in JUnit Jupiter 5.6. Users
should instead rely on a combination of other built-in conditions or
create and use a custom implementation of ExecutionCondition to
evaluate the same conditions.
Since v5.6.0 the #EnabledIf annotation was excluded. One of advantages of this one is loadContext() property, which allows to reach the goal of this topic, literally.
None of remaining annotations (e.g. EnabledIfEnvironmentVariable) contain even a tiny hint, how to reach it. And I haven't found any possibilities in the User Guide as well.
I'll appreciate any help or advice.
Indeed #EnabledIf from import org.junit.jupiter.api.condition.EnabledIf was removed in JUnit 5.6.
There is also #EnabledIf from Spring Test import org.springframework.test.context.junit.jupiter.EnabledIf which is not deprecated and fits your use case.
#EnabledIf(
expression = "#{systemProperties['your.property'].toLowerCase().contains('disabled')}",
reason = "Disabled due to property",
loadContext = true
)
#SpringBootTest
public class MyTest {
// your tests
}
Let's say you have a property inside application-foo.properties:
flaky.tests.enabled = false
You can now conditionally run the tests with
#EnabledIf(
expression = "${flaky.tests.enabled}",
reason = "Disabled flaky tests",
loadContext = true
)
#SpringBootTest
#ActiveProfiles("foo")
public class FlakyTest {
// your tests
}
I tested it with Spring Boot 2.3.0 and it works fine without any deprecation warning.

JUnit without inversion of control

Currently the JUnit5 Framework works with Inversion of Control. I.e. you annotate a test method with #Test and then JUnit scans your classpath (in the simplest case)
Now is there a way for me to be in charge of calling the test cases through JUnit APIs? Maybe by hooking my test implementations to some test registry provided by JUnit?
I'm pretty new to JUnit - how did older versions go about this?
The reason I'm asking is that normally to execute my test cases, I'd have to run something along the lines of
java -jar junit-platform-standalone.jar --class-path target --scan-class-path
on the command line. My situation requires me to run the test cases through by executing one of my own classes, like that e.g.
java /com/example/MyTestCassesLauncher
EDIT: to clarify, I need one of my own classes to be hosting/launching my test cases, something like this:
// Maybe this needs to extend one of JUnit's launchers?
public class MyTestCassesLauncher {
public static void main(String[] args) {
JUnitLauncher.launchTests(new MyTestClass());
}
}
where JUnitLauncher.launchTests is some kind of API provided by the platform. I'm not looking for a method with that exact same signature but a mechanism that would allow me to ultimately call my own MyTestClassesLauncher class to run the tests.
Thanks in advance.
Not sure what you arÄ™ actually trying to achieve but in Junit5 to change behaviour of your tests you can use Extensions mechanism, similar to Junit4 RunWith but more powerful
Such custom extension can provide some additional logic like in this logging example
public class LoggingExtension implements
TestInstancePostProcessor {
#Override
public void postProcessTestInstance(Object testInstance,
ExtensionContext context) throws Exception {
Logger logger = LogManager.getLogger(testInstance.getClass());
testInstance.getClass()
.getMethod("setLogger", Logger.class)
.invoke(testInstance, logger);
}
}
The way Junit controls it's flow is Junit problem - you should not modify framework but extend it

Parametrized Junit tests with Serenity reports

I ran into some trouble testing a Spring app. The current approach in my team is to write scenarios in Gherkin and have Serenity provide its pretty reports.
A new component in the app will need a lot of test cases. The requirements will be provided in a few 'parsable' excel files so I thought it would be neat to just use them directly, row by row, in a Junit parametrized test. Another option would be to write a bloated Gherkin feature and tediously compose each example manually.
So I thought of something like that:
#RunWith(Parameterized.class)
private static class Tests {
#Parameterized.Parameters(name = "...") // name with the params
public static Collection params() {
// parse excel here or use some other class to do it
}
#Test
public void test() {
/* do the actual test - it involves sending and receiving some JSON objects */
}
}
This works smoothly but I ran into trouble trying to use
#RunWith(SerenityRunner.class)
The problem is that Junit does not support multiple runners. A solution I found is to make a nested class and annotate each with a different runner, but I don't know how to make it work (which runner should be on the outside, where do I actually run the tests, an so on).
Any thoughts?
Actually Serenity provides another runner - SerenityParameterizedRunner which seems to have the same features as JUnit's Parameterized.

Categories

Resources