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   *
15   * @since 0.25.0
16   */
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       *
30       * <p>Custom Rule {@link ProhibitPlainJunitAssertionsRule}</p>
31       *
32       * @throws Exception If something wrong happens inside.
33       */
34      @Test
35      void prohibitsStaticImportsPlainAssertionsInTests() throws Exception {
36          new PmdAssert(
37              "PlainJUnitAssertionStaticImportBlock.java",
38              Matchers.is(false),
39              Matchers.containsString(
40                  PmdAssertionsTest.PLAIN_ASSERTIONS
41              )
42          ).assertOk();
43      }
44  
45      /**
46       * PmdValidator can prohibit plain JUnit assertion in test methods like
47       * Assert.assertEquals.
48       *
49       * <p>Custom Rule {@link ProhibitPlainJunitAssertionsRule}</p>
50       *
51       * @throws Exception If something wrong happens inside.
52       */
53      @Test
54      void prohibitsPlainJunitAssertionsInTestMethods() throws Exception {
55          new PmdAssert(
56              "PlainJUnitAssertionTestMethod.java",
57              Matchers.is(false),
58              Matchers.containsString(
59                  PmdAssertionsTest.PLAIN_ASSERTIONS
60              )
61          ).assertOk();
62      }
63  
64      /**
65       * PmdValidator can allow Assert.fail().
66       *
67       * <p>Custom Rule {@link ProhibitPlainJunitAssertionsRule}</p>
68       *
69       * @throws Exception If something wrong happens inside.
70       */
71      @Test
72      void allowsAssertFail() throws Exception {
73          new PmdAssert(
74              "AllowAssertFail.java",
75              Matchers.is(false),
76              Matchers.allOf(
77                  Matchers.not(
78                      Matchers.containsString(
79                          PmdAssertionsTest.PLAIN_ASSERTIONS
80                      )
81                  ),
82                  Matchers.containsString("UnitTestContainsTooManyAsserts")
83              )
84          ).assertOk();
85      }
86  
87      /**
88       * PmdValidator does not report UnitTestContainsTooManyAsserts when a test
89       * wraps an Assertions.assertThrows call inside an assertThat to verify the
90       * thrown exception's message.
91       *
92       * @throws Exception If something wrong happens inside.
93       */
94      @Test
95      void allowsAssertThrowsInsideAssertThat() throws Exception {
96          new PmdAssert(
97              "AssertThrowsWithMessageCheck.java",
98              Matchers.is(true),
99              Matchers.not(
100                 Matchers.containsString("UnitTestContainsTooManyAsserts")
101             )
102         ).assertOk();
103     }
104 
105     /**
106      * PmdValidator still reports UnitTestContainsTooManyAsserts when a test
107      * has multiple asserts in addition to an assertThrows call, because only
108      * assertThrows is excluded from the count.
109      *
110      * @throws Exception If something wrong happens inside.
111      */
112     @Test
113     void reportsTooManyAssertsEvenWithAssertThrows() throws Exception {
114         new PmdAssert(
115             "TooManyAssertsWithAssertThrows.java",
116             Matchers.is(false),
117             Matchers.containsString("UnitTestContainsTooManyAsserts")
118         ).assertOk();
119     }
120 
121     /**
122      * PmdValidator does not report UnitTestContainsTooManyAsserts when a test
123      * has a single assertion combined with calls such as
124      * {@code Mockito.verify(...)} or {@code pull.checks()} whose simple name
125      * starts with 'verify' or 'check' but which are not JUnit/Hamcrest
126      * assertions.
127      * Regression test for https://github.com/yegor256/qulice/issues/1606
128      *
129      * @throws Exception If something wrong happens inside.
130      */
131     @Test
132     void allowsMockitoVerifyAndChecksCalls() throws Exception {
133         new PmdAssert(
134             "AssertThatWithMockitoVerifyAndChecks.java",
135             Matchers.any(Boolean.class),
136             Matchers.not(
137                 Matchers.containsString("UnitTestContainsTooManyAsserts")
138             )
139         ).assertOk();
140     }
141 
142     /**
143      * PmdValidator can allow only package private methods, marked with: Test,
144      * RepeatedTest, TestFactory, TestTemplate or ParameterizedTest annotations.
145      *
146      * @throws Exception If something wrong happens inside.
147      */
148     @Test
149     void requiresPackagePrivateTestMethods() throws Exception {
150         new PmdAssert(
151             "TestShouldBePackagePrivate.java",
152             Matchers.is(false),
153             Matchers.containsString("JUnitJupiterTestShouldBePackagePrivate")
154         ).assertOk();
155     }
156 
157     /**
158      * PmdValidator can allow only final JUnit3 test classes.
159      *
160      * @throws Exception If something wrong happens inside.
161      */
162     @Test
163     void allowJunitThirdTestClassToBeFinal() throws Exception {
164         new PmdAssert(
165             "Junit3TestClassShouldBeFinal.java",
166             Matchers.is(false),
167             Matchers.containsString("JUnitTestClassShouldBeFinal")
168         ).assertOk();
169     }
170 
171     /**
172      * PmdValidator can allow only final JUnit4 test classes.
173      *
174      * @throws Exception If something wrong happens inside.
175      */
176     @Test
177     void allowJunitFourthTestClassToBeFinal() throws Exception {
178         new PmdAssert(
179             "Junit4TestClassShouldBeFinal.java",
180             Matchers.is(false),
181             Matchers.containsString("JUnitTestClassShouldBeFinal")
182         ).assertOk();
183     }
184 
185     /**
186      * PmdValidator can allow only final JUnit5 test classes.
187      *
188      * @throws Exception If something wrong happens inside.
189      */
190     @Test
191     void allowJunitFifthTestClassToBeFinal() throws Exception {
192         new PmdAssert(
193             "Junit5TestClassShouldBeFinal.java",
194             Matchers.is(false),
195             Matchers.containsString("JUnitTestClassShouldBeFinal")
196         ).assertOk();
197     }
198 
199     /**
200      * PmdValidator can allow only final Junit test classes.
201      *
202      * @throws Exception If something wrong happens inside.
203      */
204     @Test
205     void allowJunitTestClassToBeFinal() throws Exception {
206         new PmdAssert(
207             "JunitTestClassIsFinal.java",
208             Matchers.is(false),
209             Matchers.allOf(
210                 Matchers.not(
211                     Matchers.containsString("JUnitTestClassShouldBeFinal")
212                 ),
213                 Matchers.containsString("UnitTestShouldIncludeAssert")
214             )
215         ).assertOk();
216     }
217 
218     /**
219      * PmdValidator can find assert() calls placed inside a lambda
220      * body and not report UnitTestShouldIncludeAssert violation.
221      *
222      * @throws Exception If something wrong happens inside.
223      */
224     @Test
225     void findsAssertionInsideLambdaBody() throws Exception {
226         new PmdAssert(
227             "AssertInsideLambda.java",
228             Matchers.is(true),
229             Matchers.not(
230                 Matchers.containsString("UnitTestShouldIncludeAssert")
231             )
232         ).assertOk();
233     }
234 
235     /**
236      * PmdValidator recognises the cactoos-matchers convention of a
237      * no-argument {@code affirm()} call on an {@code Assertion} object as a
238      * valid assertion and does not report UnitTestShouldIncludeAssert.
239      * Regression test for https://github.com/yegor256/qulice/issues/1698
240      *
241      * @throws Exception If something wrong happens inside.
242      */
243     @Test
244     void findsAssertionInAffirmCall() throws Exception {
245         new PmdAssert(
246             "AssertionAffirm.java",
247             Matchers.is(true),
248             Matchers.not(
249                 Matchers.containsString("UnitTestShouldIncludeAssert")
250             )
251         ).assertOk();
252     }
253 
254     /**
255      * PmdValidator does not flag classes that use non-JUnit test conventions
256      * like g4s8/oot, where a class ends with {@code *Test} but uses a
257      * {@code public static void test()} entry point instead of
258      * {@code @Test}-annotated methods.
259      * Regression test for https://github.com/yegor256/qulice/issues/1064
260      *
261      * @throws Exception If something wrong happens inside.
262      */
263     @Test
264     void allowsNonJunitTestClassesWithStaticTestMethod() throws Exception {
265         new PmdAssert(
266             "OotStyleTest.java",
267             Matchers.any(Boolean.class),
268             Matchers.allOf(
269                 Matchers.not(
270                     Matchers.containsString("TestClassWithoutTestCases")
271                 ),
272                 Matchers.not(
273                     Matchers.containsString(
274                         "UnitTestShouldUseTestAnnotation"
275                     )
276                 )
277             )
278         ).assertOk();
279     }
280 
281     /**
282      * PmdValidator does not report JUnitAssertionsShouldIncludeMessage
283      * (a.k.a. UnitTestAssertionsShouldIncludeMessage) when a test uses the
284      * Hamcrest two-argument form
285      * {@link org.hamcrest.MatcherAssert#assertThat(String, boolean)} where
286      * the first argument already is the message.
287      * Regression test for https://github.com/yegor256/qulice/issues/1315
288      *
289      * @throws Exception If something wrong happens inside.
290      */
291     @Test
292     void allowsMatcherAssertThatWithBooleanAndMessage() throws Exception {
293         new PmdAssert(
294             "MatcherAssertBooleanWithMessage.java",
295             Matchers.any(Boolean.class),
296             Matchers.not(
297                 Matchers.containsString(
298                     "UnitTestAssertionsShouldIncludeMessage"
299                 )
300             )
301         ).assertOk();
302     }
303 
304     /**
305      * PmdValidator still reports UnitTestAssertionsShouldIncludeMessage when
306      * the two-argument form of
307      * {@link org.hamcrest.MatcherAssert#assertThat(Object, org.hamcrest.Matcher)}
308      * is used without a reason. Guards the fix for
309      * https://github.com/yegor256/qulice/issues/1315 from over-suppressing.
310      *
311      * @throws Exception If something wrong happens inside.
312      */
313     @Test
314     void reportsMatcherAssertThatWithoutMessage() throws Exception {
315         new PmdAssert(
316             "MatcherAssertWithoutMessage.java",
317             Matchers.is(false),
318             Matchers.containsString(
319                 "UnitTestAssertionsShouldIncludeMessage"
320             )
321         ).assertOk();
322     }
323 }