In IntelliJ, with a Springboot project (2.6.6) using JUnit 5, given the following test class, IntelliJ doesn't display exceptions occuring in the #BeforeAll method.
#ExtendWith(SpringExtension.class)
public class SpringTest {
private Object OBJECT = new Object();
#BeforeAll
public static void before() {
throw new RuntimeException("SpringTest.RuntimeException"); // replace by actual business code
}
#Test
public void test() {
// Doesn't matter
assertNotNull(this.OBJECT);
}
Running the class within IntelliJ (only this class)
Running the package of the test
When the #BeforeAll method is more complex, it's hard to understand that an exception occured, until you run the whole test package by chance.
In JUnit 4 with a #Before method, IntelliJ was showing test failure, with the stacktrace of the exception (which makes things easier to debug).
My pom.xml only dependencies are spring-boot-starter & spring-boot-starter-test.
Is this a bug / Is there any solution to reproduce the old behaviour ?
Stack:
Spring boot 2.6.6 / JUnit 5
IntelliJ IDEA 2022.1 Build #IU-221.5080.210
OpenJDK_x64Temurin_11.0.14.1_1 / Maven-3.8.4
Edit
As pointed out in the comment, to reproduce #Before of JUnit4, you should use #BeforeEach in Junit 5. In this case, IntelliJ will behave as before and display exceptions even when running only the given test class.
For the #BeforeAll, question is still pending.
Edit 2
A bug has been opened for the #BeforeAll exceptions: https://youtrack.jetbrains.com/issue/IDEA-292662
Bug resolved in IntelliJ 2022.1.1 Preview.
See YouTrack: IDEA-292662
Related
Currently going through the process of upgrading from Junit4 to Junit5 and running into a bit of a hurdle with something that used to work in Junit4.
Wondering if there is a way to access the #BeforeAll/#AfterAll (formerly #BeforeClass/#AfterClass) within a class which is also a #Suite
Example:
#Suite
#SelectClasses({
SquareService.class,
TriangleService.class
})
public class ShapeTestSuite {
#BeforeAll
public void beforeAll() {
Log.info("Shape Test Suite Start!");
}
#AfterAll
public void afterAll() {
Log.info("Shape Test Suite End!");
}
}
I've tried adding an extension to this class/suite, but that also does not seem to work. What am I missing? Any help would be greatly appreciated.
Thanks
#BeforeAll and #AfterAll runs before any execution of #Test, #TestFactory, etc.
So if you create one them you will see that your code will be run correctly.
#BeforeAll and #AfterAll are annotations from Jupiter, which is one (of many) JUnit 5 engines. #Suite, however, is independent and can run tests and test suites combined from any JUnit 5 engine. That’s why you cannot use a before-all method in a suite class.
I'm using WireMock in my tests and have such a line of code:
#Rule
public WireMockRule wireMockRule = new WireMockRule(8080);
I want to switch to JUnit 5. So I added the next dependency (using Gradle):
testCompile('org.junit.jupiter:junit-jupiter-engine:5.1.1')
But there are no suggestions when I'm trying to import #Rule annotation.
Do I need to add another module of JUnit dependency? Or are rules not supported in JUnit 5? If not, how can I replace #Rule annotation to make tests work again?
In a general way, what you did with #Rule and #ClassRule in JUnit 4 should be done with #ExtendWith and Extension that associated provide a very close feature in JUnit 5.
It works as standards JUnit lifecycle hooks but that it is extracted in a Extension class. And similarly to #Rule, as many Extensions as required may be added for a test class.
To handle the issue you have several possible approaches among :
keep the JUnit 4 way (JUnit 5 owns the JUnit Vintage part that allows to execute JUnit 3 or 4 tests).
rewrite the #Rule as an Extension.
do the actual processing done by WireMockRule (start the server, execute your tests and stop the server) in each test of class with #BeforeEach and #AfterEach hook methods.
use a third library that implements the equivalent of WireMockRule in the JUnit 5 Extension way such as https://github.com/lanwen/wiremock-junit5
Note that your issue already discussed in the JUnit 5 Issues.
JUnit 4 annotations #Rule and #ClassRule do not exist in JUnit 5. Basically there is a new extension model that can be used to implement extensions with the same functionality. These extensions can be used with the #ExtendWith annotation.
There is a limited migration support for a subset of JUnit 4 rules in the junit-jupiter-migrationsupport module. Unfortunately, it's only limited to subclasses of ExternalResource and Verifier.
Before wiremock has official support for JUnit you have some workarounds:
Run JUnit 4 tests side by side with JUnit 5 tests with the junit-vintage-engine.
Start and stop the server yourself in the test code.
Use a 3rd party extension like wiremock-junit5 or wiremock-extension.
There is now official support for JUnit 5 Jupiter from WireMock 2.31.0.
Docs here: http://wiremock.org/docs/junit-jupiter/
The https://github.com/webcompere/java-test-gadgets project lets you solve this in a couple of ways.
You can use its support for JUnit 4 rules via the DangerousRuleAdapter - which will attempt to turn any JUnit 4 rule into a Plugin:
#ExtendWith(PluginExtension.class)
public class DangerousRuleAdapterExampleTest {
#Plugin
private DangerousRuleAdapter<WireMockRule> adapter =
new DangerousRuleAdapter<>(new WireMockRule());
#Test
void theTest() {
// use wiremock rule here
WireMockRule rule = adapter.get();
}
The rule adapters cannot work with rules that inspect the test class or the test method, but make a good attempt at running the rule.
There's also support for running a rule around some code:
TemporaryFolder temporaryFolder = new TemporaryFolder();
// let's use this temp folder with some test code
executeWithRule(temporaryFolder, () -> {
// here, the rule is _active_
callSomethingThatUses(temporaryFolder.getRoot());
});
And you can easily create your own new JUnit 5 plugin by using the PluginExtension and TestResource.of
#ExtendWith(PluginExtension.class)
class TestResourceIsActiveDuringTest {
private WireMockServer server;
#Plugin
private TestResource someResource = TestResource.from(() -> server.start(),
() -> server.stop());
From the JUnit 5 user guide:
#Rule and #ClassRule no longer exist; superseded by #ExtendWith and #RegisterExtension. See also "Limited JUnit 4 Rule Support".
However, as pointed out by Tom, WireMock has full JUnit Jupiter support since version 2.31.0:
// New JUnit 5 extension
#WireMockTest
class DeclarativeWireMockTest {
#Test
void test_something_with_wiremock(WireMockRuntimeInfo wmRuntimeInfo) {
// The static DSL will be automatically configured for you
stubFor(get("/static-dsl").willReturn(ok()));
// Instance DSL can be obtained from the runtime info parameter
WireMock wireMock = wmRuntimeInfo.getWireMock();
wireMock.register(get("/instance-dsl").willReturn(ok()));
// Info such as port numbers is also available
int port = wmRuntimeInfo.getHttpPort();
// Do some testing...
}
}
For more information, please refer to the corresponding docs.
i have a problem which occurs when using NetBeans 8.2 and JUnit.
Considering the following example:
Unit Test:
private MyClass myClass = new MyClass();
#Test
public void testSomething() {
myClass.testMethod();
}
// OTHER TEST EXISTING BUT THESE ARE TAGGED WITH #IGNORE
If I am using the following production code:
MyClass:
public class MyClass {
public void testMethod() {
System.out.print("test");
}
}
The "Unit test output" in NetBeans displays something like:
test
Testcase: testSomethingOther(mypackage.MyClassTest):SKIPPED
Testcase: testSomethingOther2(mypackage.MyClassTest):SKIPPED
-- other tests which are ignored / failed --
But I only want NetBeans to display my own "print" statements, and not some Test details.
If i am using the "println" function, it works as as planned (no test details are written to output console).
What is the problem here?
You're using the annotation #Test which implies that you're probably using JUnit, TestNG or another Testing framework. If you don't want to see your framework's prints either check if there's a configuration setting / flag that you can pass that turns it off or stop using it and find another way to run your tests.
When writing code that interacts with external resources (such as using a web service or other network operation), I often structure the classes so that it can also be "stubbed" using a file or some other input method. So then I end up using the stubbed implementation to test other parts of the system and then one or two tests that specifically test calling the web service.
The problem is I don't want to be calling these external services either from Jenkins or when I run all of the tests for my project (e.g. "gradle test"). Some of the services have side effects, or may not be accessible to all developers.
Right now I just uncomment and then re-comment the #Test annotation on these particular test methods to enable and disable them. Enable it, run it manually to check it, then remember to comment it out again.
// Uncomment to test external service manually
//#Test
public void testSomethingExternal() {
Is there is a better way of doing this?
EDIT: For manual unit testing, I use Eclipse and am able to just right-click on the test method and do Run As -> JUnit test. But that doesn't work without the (uncommented) annotation.
I recommend using junit categories. See this blog for details : https://community.oracle.com/blogs/johnsmart/2010/04/25/grouping-tests-using-junit-categories-0.
Basically, you can annotate some tests as being in a special category and then you can set up a two test suites : one that runs the tests of that category and one that ignores tests in that category (but runs everything else)
#Category(IntegrationTests.class)
public class AccountIntegrationTest {
#Test
public void thisTestWillTakeSomeTime() {
...
}
#Test
public void thisTestWillTakeEvenLonger() {
....
}
}
you can even annotate individual tests"
public class AccountTest {
#Test
#Category(IntegrationTests.class)
public void thisTestWillTakeSomeTime() {
...
}
Anytime I see something manually getting turned on or off I cringe.
As far as I can see you use gradle and API for JUnit says that annotation #Ignore disables test. I will add gradle task which will add #Ignore for those tests.
If you're just wanting to disable tests for functionality that hasn't been written yet or otherwise manually disable some tests temporarily, you can use #Ignore; the tests will be skipped but still noted in the report.
If you are wanting something like Spring Profiles, where you can define rulesets for which tests get run when, you should either split up your tests into separate test cases or use a Filter.
You can use #Ignore annotation to prevent them from running automatically during test. If required, you may trigger such Ignored tests manually.
#Test
public void wantedTest() {
return checkMyFunction(10);
}
#Ignore
#Test
public void unwantedTest() {
return checkMyFunction(11);
}
In the above example, unwantedTest will be excluded.
I have the following test case in eclipse, using JUnit 4 which is refusing to pass. What could be wrong?
#Test(expected = IllegalArgumentException.class)
public void testIAE() {
throw new IllegalArgumentException();
}
This exact testcase came about when trying to test my own code with the expected tag didn't work. I wanted to see if JUnit would pass the most basic test. It didn't.
I've also tested with custom exceptions as expected without luck.
Screenshot:
The problem is that your AnnounceThreadTest extends TestCase. Because it extends TestCase, the JUnit Runner is treating it as a JUnit 3.8 test, and the test is running because it starts with the word test, hiding the fact that the #Test annotiation is in fact not being used at all.
To fix this, remove the "extends TestCase" from the class definition.
Just ran this in IntelliJ using JUnit 4.4:
#Test(expected = IllegalArgumentException.class)
public void testExpected()
{
throw new IllegalArgumentException();
}
Passes perfectly.
Rebuild your entire project and try again. There's something else that you're doing wrong. JUnit 4.4 is working as advertised.
Instead of removing extends TestCase , you can add this to run your test case with Junit4 which supports annotation.
#RunWith(JUnit4.class)