[java] UnitTestShouldUseBeforeAnnotation: Consider JUnit 5 and TestNG

This commit is contained in:
Andreas Dangel 2024-10-03 17:01:24 +02:00
parent b7c4a5e492
commit 33c737718c
No known key found for this signature in database
GPG Key ID: 93450DF2DF9A3FA3
3 changed files with 159 additions and 85 deletions

View File

@ -16,6 +16,9 @@ This is a {{ site.pmd.release_type }} release.
### 🌟 Rule Changes
#### Changed Rules
* {% rule java/bestpractices/UnitTestShouldUseBeforeAnnotation %} (Java Best Practices) now also considers JUnit 5 and TestNG tests.
#### Renamed Rules
Several rules for unit testing have been renamed to better reflect their actual scope. Lots of them were called
after JUnit / JUnit 4, even when they applied to JUnit 5 and / or TestNG.

View File

@ -1342,16 +1342,20 @@ public class MyTest2 {
<rule name="UnitTestShouldUseBeforeAnnotation"
language="java"
since="4.0"
message="JUnit 4 tests that set up tests should use the @Before annotation, JUnit5 tests should use @BeforeEach or @BeforeAll"
message="Apply the correct annotation if this method is used to set up the tests"
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#unittestshouldusebeforeannotation">
<description>
This rule detects methods called `setUp()` that are not properly annotated as a setup method.
This is primarily intended to assist in upgrading from JUnit 3, where setup methods were required to be called `setUp()`.
To a lesser extent, this may help detect omissions even under newer JUnit versions, as long as you are following this convention to name the methods.
To a lesser extent, this may help detect omissions even under newer JUnit versions or under TestNG,
as long as you are following this convention to name the methods.
JUnit 4 will only execute methods annotated with `@Before` before all tests.
JUnit 5 introduced `@BeforeEach` and `@BeforeAll` annotations to execute methods before each test or before all tests in the class, respectively.
* JUnit 4 will only execute methods annotated with `@Before` before all tests.
* JUnit 5 introduced `@BeforeEach` and `@BeforeAll` annotations to execute methods before each test or before all
tests in the class, respectively.
* TestNG provides the annotations `@BeforeMethod` and `@BeforeClass` to execute methods before each test or before
tests in the class, respectively.
</description>
<priority>3</priority>
<properties>
@ -1363,9 +1367,15 @@ public class MyTest2 {
pmd-java:typeIs('org.junit.Before')
or pmd-java:typeIs('org.junit.jupiter.api.BeforeEach')
or pmd-java:typeIs('org.junit.jupiter.api.BeforeAll')
or pmd-java:typeIs('org.testng.annotations.BeforeMethod')])]
(: Make sure this is a junit 4 class :)
[../MethodDeclaration[pmd-java:hasAnnotation('org.junit.Test')]]
or pmd-java:typeIs('org.testng.annotations.BeforeMethod')
or pmd-java:typeIs('org.testng.annotations.BeforeClass')
])]
(: Make sure this is a JUnit 4/5 or TestNG class :)
[../MethodDeclaration[
pmd-java:hasAnnotation('org.junit.Test')
or pmd-java:hasAnnotation('org.junit.jupiter.api.Test')
or pmd-java:hasAnnotation('org.testng.annotations.Test')
]]
]]>
</value>
</property>

View File

@ -5,8 +5,9 @@
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
<test-code>
<description>Contains setUp</description>
<description>JUnit4 Test class contains setUp</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>3</expected-linenumbers>
<code><![CDATA[
import org.junit.Test;
public class Foo {
@ -20,7 +21,7 @@ public class Foo {
</test-code>
<test-code>
<description>Contains @setUp</description>
<description>JUnit4 Test class with Before is ok</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.junit.Before;
@ -37,7 +38,7 @@ public class Foo {
</test-code>
<test-code>
<description>Renamed setup</description>
<description>JUnit4 Test class with renamed setup using Before is ok</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.junit.Before;
@ -73,83 +74,27 @@ public class Foo {
</test-code>
<test-code>
<description>#1446 False positive with JUnit4TestShouldUseBeforeAnnotation when TestNG is used</description>
<description>Contains setUp, not a JUnit 4/5/TestNG test</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.lang.reflect.Method;
public class Foo {
@BeforeMethod
public void setUp(Method m) {
//...
}
@Test
public void someTest() {}
public void setUp() {}
public void foo() {}
}
]]></code>
</test-code>
<test-code>
<description>#940 False positive with JUnit4TestShouldUseBeforeAnnotation when JUnit5's 'BeforeEach' is used</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.junit.jupiter.api.*;
public class Foo {
@BeforeEach
public void setUp() {
//...
}
@Test
public void someTest() {}
}
]]></code>
</test-code>
<test-code>
<description>#940 False positive with JUnit4TestShouldUseBeforeAnnotation when JUnit5's 'BeforeAll' is used</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.junit.jupiter.api.*;
public class Foo {
@BeforeAll
public void setUp() {
//...
}
@Test
public void someTest() {}
}
]]></code>
</test-code>
<test-code>
<description>Contains setUp, not a junit 4 test</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
public void setUp() {
}
public void foo() {
}
}
]]></code>
</test-code>
<test-code>
<description>Contains setUp with different signature</description>
<description>JUnit4 Test class contains setUp with different signature is ok</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.junit.Test;
public class Foo {
public void setUp(int something) {
}
public void setUp(int something) {}
@Test
public void foo() {
}
public void foo() {}
}
]]></code>
</test-code>
@ -170,6 +115,122 @@ public class AReallyCoolFeatureTest extends BaseTest {
public void tearDown() {
super.tearDown();
}
}
]]></code>
</test-code>
<test-code>
<description>TestNG class contains setUp</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>4</expected-linenumbers>
<code><![CDATA[
import org.testng.annotations.Test;
public class MyTestCase {
public void setUp() {} // violation expected here
@Test
public void myTest() {}
}
]]></code>
</test-code>
<test-code>
<description>TestNG class contains setUp with different signature is ok (#1446)</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.testng.annotations.Test;
import java.lang.reflect.Method;
public class Foo {
public void setUp(Method m) {}
@Test
public void foo() {}
}
]]></code>
</test-code>
<test-code>
<description>TestNG with @BeforeMethod is ok (#1446)</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class MyTestCase {
@BeforeMethod
public void setUp() {}
@Test
public void myTest() {}
}
]]></code>
</test-code>
<test-code>
<description>TestNG with @BeforeClass is ok</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class MyTestCase {
@BeforeClass
public void setUp() {}
@Test
public void myTest() {}
}
]]></code>
</test-code>
<test-code>
<description>JUnit5 Test class contains setUp</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>4</expected-linenumbers>
<code><![CDATA[
import org.junit.jupiter.api.Test;
public class MyTestCase {
public void setUp() {} // violation expected
@Test
public void myTest() {}
}
]]></code>
</test-code>
<test-code>
<description>JUnit5 Test class with BeforeEach is ok (#940)</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class MyTestCase {
@BeforeEach
public void setUp() {}
@Test
public void myTest() {}
}
]]></code>
</test-code>
<test-code>
<description>JUnit5 Test class with BeforeAll is ok (#940)</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class MyTestCase {
@BeforeAll
public void setUp() {}
@Test
public void myTest() {}
}
]]></code>
</test-code>