JUnit without inversion of control - java

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

Related

Java - Wiremock - Multiple Components

I've been trying to get this guide to work from Wiremock's documentation:
https://wiremock.org/docs/junit-jupiter/ - Advanced usage - programmatic
As I want to be able to mock multiple hosts simultaneously (same host, unique ports for my local environment). But I don't want these #RegisterExtension to be located in my test classes, instead in separate files but in doing so JUnit doesn't pick them up and I can't figure out why. Am I going about it in the wrong way?
Test code:
public class MyTest{
#Test
public void testMe(){
MyIntegration.mock();
}
}
public MyIntegration{
#RegisterExtension
static WireMockExtension wiremock = WireMockExtension.newInstance(wireMockConfig().port(9000)).build();
public static void mock(){
var info = wiremock.getRuntimeInfo(); // wireMockServer is null
wiremock.stubFor(...); // NPE
}
}
JUnit Jupiter scans test classes for #RegisterExtension annotations and runs the lifecycle methods on the annotated objects, but it won't scan non-test classes, which is why the server isn't being started in your example.
You have two options:
Create a base class with the WireMockExtension instances in it, then make each test class extend this.
In your integration class, new up an instance of WireMockServer, then make sure you call the start() and stop() methods on it before/after your test cases.
My preference is usually 1) in this scenario.

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.

JUnit 5, pass information from test class to extension

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

How do I test Java code that uses JAR?

I have Java code that uses JAR:
public class Version {
public String getVersion() {
// Use Java Package API to return information specified in the manifest of this JAR.
return getClass().getPackage().getImplementationVersion();
}
}
How do I run JUnit test for this code?
It fails in development build (in Eclipse) since there is no JAR file yet.
It fails in production build (in Gradle) since there is no JAR file yet.
You always need to mock the dependencies for your unit testing. Boundary is unit test your code and not the jar itself. Mockito framework is good and there are other frameworks that do the job.
Chances are, that this can't be properly mocked (and thus: not unit tested). The point is that you are actually calling a method on "this". But you can't test some object ... and mock it at the same time.
You see, if your production code would look like this:
public String getVersion() {
return someObject.getClass().....
}
then you could create a mock object; and insert that into your Version class. But even then, the method getClass() is final within java.lang.Object; and therefore you can't be mocking it anyway.
[ Reasonable mocking frameworks like EasyMock or Mokito work by extending classes and overriding the methods you want to control. There are frameworks like PowerMock that do byte code manipulation and that allow for this kind of mocking - but you should never ever use such libraries; as they have really bad side effects (like breaking most coverage libraries) ]
What might work:
class Version {
private final Package packageForVersionCheck;
public Version() {
this(getClass().getPackage()));
}
Version(Package somePackage) {
this.packageForVersionCheck = ...
}
public String getVersion() {
return this.packageForVersionCheck.getImpl....
Now you can use dependency injection to provide a "mocked" package that returns that string. But well, that looks like a lot of code for almost no gain.
Long story short: sometimes, you simply can't write a reasonable unit test. Then do the next best thing: create some "functional" test that is automatically executed in a "customer like" setup; and make sure that you have an automated setup to run such tests, too.

How can I make JUnit 4.8 run code after a failed test, but before any #After methods?

I'm driving a suite of Selenium tests (actually WebDriver-backed Selenium) using JUnit 4.8.2. I'd like the tests to automatically take a screenshot of the browser as soon as the test fails an assertion. All the tests inherit from SeleniumBaseTestCase, and the majority then further inherit from from SeleniumBastTestCaseWithCompany (which uses #Before and #After methods to create and then clean up common test data via Selenium).
I've tried adding a subclass of TestWatchman as a #Rule in SeleniumBaseTestCase, overriding TestWatchman's failed method to take the screenshot. The trouble is that the #After methods cleaning up the test data are being run before TestWatchman's failed method is called, so the screenshots are all of the final step of the clean-up, not the test that failed.
Looking into it a little, it seems that TestWatchman's apply method just calls the passed Statement's evaluate method (the only exposed method), which calls the #After methods, leaving TestWatchman (or any other Rule) no chance to insert any code between the execution of the test and of the #After methods, as far as I can tell.
I've also seen approaches that create a custom Runner to alter the Statements created so that methods annotated with the custom #AfterFailure are run before #After methods (so the screenshot can be taken in such an #AfterFailure method), but this relies on overriding BlockJUnit4ClassRunner's withAfters method, which is deprecated and due to become private, according to the documentation, which suggests using Rules instead.
I've found another answer on SO about the #Rule lifecycle that makes it sound like this simply might not be possible in JUnit 4.8, but may be possible in JUnit 4.10. If that's correct then fair enough, I'd just like confirmation of that first.
Any thoughts on an elegant and future-proof way in which I can achieve what I want would be much appreciated!
You are right in your analysis, #Befores and #Afters are added to the list of Statements before any Rules. The #Before gets executed after the #Rule and the #After gets executed before the #Rule. How you fix this depends on how flexible you can be with SeleniumBaseTestCaseWithCompany.
The easiest way would be to remove your #Before/#After methods and replace them with an ExternalResource. This could look something like:
public class BeforeAfterTest {
#Rule public TestRule rule = new ExternalResource() {
protected void before() throws Throwable { System.out.println("externalResource before"); }
protected void after() { System.out.println("externalResource after"); }
};
#Test public void testHere() { System.out.println("testHere"); }
}
this gives:
externalResource before
testHere
externalResource after
This field can be put into your base class, so it gets inherited/overridden. Your problem with ordering between #After and your rules then goes away, because you can order your rules how you like, using #RuleChain (in 4.10, not 4.8).
If you can't change SeleniumBaseTestCaseWithCompany, then you can extend BlockJUnit4ClassRunner, but don't override withAfters, but override BlockJUnit4ClassRunner#methodBlock(). You can then call super.methodBlock, and reorder the Statements as necessary[*].
[*]You could just copy the code, and reorder the lines, but withRules is private and therefore not callable from a subclass.

Categories

Resources