View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.pmd;
6   
7   import com.qulice.pmd.rules.ProhibitPlainJunitAssertionsRule;
8   import org.hamcrest.Matchers;
9   import org.junit.jupiter.api.Test;
10  
11  /**
12   * Test case for {@link PmdValidator} covering JUnit assertion rules and
13   * related test-class conventions.
14   * @since 0.25.0
15   */
16  @SuppressWarnings("PMD.TooManyMethods")
17  final class PmdAssertionsTest {
18  
19      /**
20       * Pattern using plain JUnit assertions.
21       */
22      private static final String PLAIN_ASSERTIONS =
23          "Avoid using Plain JUnit assertions";
24  
25      /**
26       * PmdValidator can prohibit plain JUnit assertion in import block like
27       * import static org.junit.Assert.assert* import static
28       * junit.framework.Assert.assert*.
29       * <p>
30       * Custom Rule {@link ProhibitPlainJunitAssertionsRule}
31       * @throws Exception If something wrong happens inside.
32       */
33      @Test
34      void prohibitsStaticImportsPlainAssertionsInTests() throws Exception {
35          new PmdAssert(
36              "PlainJUnitAssertionStaticImportBlock.java",
37              Matchers.is(false),
38              Matchers.containsString(
39                  PmdAssertionsTest.PLAIN_ASSERTIONS
40              )
41          ).assertOk();
42      }
43  
44      /**
45       * PmdValidator can prohibit plain JUnit assertion in test methods like
46       * Assert.assertEquals.
47       * <p>
48       * Custom Rule {@link ProhibitPlainJunitAssertionsRule}
49       * @throws Exception If something wrong happens inside.
50       */
51      @Test
52      void prohibitsPlainJunitAssertionsInTestMethods() throws Exception {
53          new PmdAssert(
54              "PlainJUnitAssertionTestMethod.java",
55              Matchers.is(false),
56              Matchers.containsString(
57                  PmdAssertionsTest.PLAIN_ASSERTIONS
58              )
59          ).assertOk();
60      }
61  
62      /**
63       * PmdValidator can allow Assert.fail().
64       * <p>
65       * Custom Rule {@link ProhibitPlainJunitAssertionsRule}
66       * @throws Exception If something wrong happens inside.
67       */
68      @Test
69      void allowsAssertFail() throws Exception {
70          new PmdAssert(
71              "AllowAssertFail.java",
72              Matchers.is(false),
73              Matchers.allOf(
74                  Matchers.not(
75                      Matchers.containsString(
76                          PmdAssertionsTest.PLAIN_ASSERTIONS
77                      )
78                  ),
79                  Matchers.containsString("UnitTestContainsTooManyAsserts")
80              )
81          ).assertOk();
82      }
83  
84      /**
85       * PmdValidator does not report UnitTestContainsTooManyAsserts when a test
86       * wraps an Assertions.assertThrows call inside an assertThat to verify the
87       * thrown exception's message.
88       * @throws Exception If something wrong happens inside.
89       */
90      @Test
91      void allowsAssertThrowsInsideAssertThat() throws Exception {
92          new PmdAssert(
93              "AssertThrowsWithMessageCheck.java",
94              Matchers.is(true),
95              Matchers.not(
96                  Matchers.containsString("UnitTestContainsTooManyAsserts")
97              )
98          ).assertOk();
99      }
100 
101     /**
102      * PmdValidator still reports UnitTestContainsTooManyAsserts when a test
103      * has multiple asserts in addition to an assertThrows call, because only
104      * assertThrows is excluded from the count.
105      * @throws Exception If something wrong happens inside.
106      */
107     @Test
108     void reportsTooManyAssertsEvenWithAssertThrows() throws Exception {
109         new PmdAssert(
110             "TooManyAssertsWithAssertThrows.java",
111             Matchers.is(false),
112             Matchers.containsString("UnitTestContainsTooManyAsserts")
113         ).assertOk();
114     }
115 
116     /**
117      * PmdValidator can allow only package private methods, marked with: Test,
118      * RepeatedTest, TestFactory, TestTemplate or ParameterizedTest annotations.
119      * @throws Exception If something wrong happens inside.
120      */
121     @Test
122     void requiresPackagePrivateTestMethods() throws Exception {
123         new PmdAssert(
124             "TestShouldBePackagePrivate.java",
125             Matchers.is(false),
126             Matchers.containsString("JUnit5TestShouldBePackagePrivate")
127         ).assertOk();
128     }
129 
130     /**
131      * PmdValidator can allow only final JUnit3 test classes.
132      * @throws Exception If something wrong happens inside.
133      */
134     @Test
135     void allowJunitThirdTestClassToBeFinal() throws Exception {
136         new PmdAssert(
137             "Junit3TestClassShouldBeFinal.java",
138             Matchers.is(false),
139             Matchers.containsString("JUnitTestClassShouldBeFinal")
140         ).assertOk();
141     }
142 
143     /**
144      * PmdValidator can allow only final JUnit4 test classes.
145      * @throws Exception If something wrong happens inside.
146      */
147     @Test
148     void allowJunitFourthTestClassToBeFinal() throws Exception {
149         new PmdAssert(
150             "Junit4TestClassShouldBeFinal.java",
151             Matchers.is(false),
152             Matchers.containsString("JUnitTestClassShouldBeFinal")
153         ).assertOk();
154     }
155 
156     /**
157      * PmdValidator can allow only final JUnit5 test classes.
158      * @throws Exception If something wrong happens inside.
159      */
160     @Test
161     void allowJunitFifthTestClassToBeFinal() throws Exception {
162         new PmdAssert(
163             "Junit5TestClassShouldBeFinal.java",
164             Matchers.is(false),
165             Matchers.containsString("JUnitTestClassShouldBeFinal")
166         ).assertOk();
167     }
168 
169     /**
170      * PmdValidator can allow only final Junit test classes.
171      * @throws Exception If something wrong happens inside.
172      */
173     @Test
174     void allowJunitTestClassToBeFinal() throws Exception {
175         new PmdAssert(
176             "JunitTestClassIsFinal.java",
177             Matchers.is(false),
178             Matchers.allOf(
179                 Matchers.not(
180                     Matchers.containsString("JUnitTestClassShouldBeFinal")
181                 ),
182                 Matchers.containsString("UnitTestShouldIncludeAssert")
183             )
184         ).assertOk();
185     }
186 
187     /**
188      * PmdValidator can find assert() calls placed inside a lambda
189      * body and not report UnitTestShouldIncludeAssert violation.
190      * @throws Exception If something wrong happens inside.
191      */
192     @Test
193     void findsAssertionInsideLambdaBody() throws Exception {
194         new PmdAssert(
195             "AssertInsideLambda.java",
196             Matchers.is(true),
197             Matchers.not(
198                 Matchers.containsString("UnitTestShouldIncludeAssert")
199             )
200         ).assertOk();
201     }
202 
203     /**
204      * PmdValidator does not flag classes that use non-JUnit test conventions
205      * like g4s8/oot, where a class ends with {@code *Test} but uses a
206      * {@code public static void test()} entry point instead of
207      * {@code @Test}-annotated methods.
208      * Regression test for https://github.com/yegor256/qulice/issues/1064
209      * @throws Exception If something wrong happens inside.
210      */
211     @Test
212     void allowsNonJunitTestClassesWithStaticTestMethod() throws Exception {
213         new PmdAssert(
214             "OotStyleTest.java",
215             Matchers.any(Boolean.class),
216             Matchers.allOf(
217                 Matchers.not(
218                     Matchers.containsString("TestClassWithoutTestCases")
219                 ),
220                 Matchers.not(
221                     Matchers.containsString(
222                         "UnitTestShouldUseTestAnnotation"
223                     )
224                 )
225             )
226         ).assertOk();
227     }
228 
229     /**
230      * PmdValidator does not report JUnitAssertionsShouldIncludeMessage
231      * (a.k.a. UnitTestAssertionsShouldIncludeMessage) when a test uses the
232      * Hamcrest two-argument form
233      * {@link org.hamcrest.MatcherAssert#assertThat(String, boolean)} where
234      * the first argument already is the message.
235      * Regression test for https://github.com/yegor256/qulice/issues/1315
236      * @throws Exception If something wrong happens inside.
237      */
238     @Test
239     void allowsMatcherAssertThatWithBooleanAndMessage() throws Exception {
240         new PmdAssert(
241             "MatcherAssertBooleanWithMessage.java",
242             Matchers.any(Boolean.class),
243             Matchers.not(
244                 Matchers.containsString(
245                     "UnitTestAssertionsShouldIncludeMessage"
246                 )
247             )
248         ).assertOk();
249     }
250 
251     /**
252      * PmdValidator still reports UnitTestAssertionsShouldIncludeMessage when
253      * the two-argument form of
254      * {@link org.hamcrest.MatcherAssert#assertThat(Object, org.hamcrest.Matcher)}
255      * is used without a reason. Guards the fix for
256      * https://github.com/yegor256/qulice/issues/1315 from over-suppressing.
257      * @throws Exception If something wrong happens inside.
258      */
259     @Test
260     void reportsMatcherAssertThatWithoutMessage() throws Exception {
261         new PmdAssert(
262             "MatcherAssertWithoutMessage.java",
263             Matchers.is(false),
264             Matchers.containsString(
265                 "UnitTestAssertionsShouldIncludeMessage"
266             )
267         ).assertOk();
268     }
269 }