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 }