0

Our project uses assert methods from assertj library as well in some of the unit test methods. So the current cypher rule to search for assert method doesn't identify assert methods like below and flags them as violations.

assertThat("x").isEqualTo("Y"); in the unit test methods.

how to modify the script to consider any "assert*" invocations from unit test method.

      <cypher><![CDATA[
        MATCH
            (c:Type:Class)-[:DECLARES]->(m:Method:JunitTestMethod),
            (m)-[:INVOKES*..10]->(assert:Method)
        WHERE
            assert.signature =~ "void assert.*"
            OR assert.signature =~ "void fail.*"
            OR assert.signature =~ "void verify.*"

        SET
            m:JunitTestWithAssert
        RETURN
            c.fqn AS TestClass, m.name AS TestMethodWithAssert
        ]]></cypher>

Sample Test method :

        @Test
        public void testAssertWithDiffLibrary() {
          String testName = "Hello";
          assertThat(testName).isEqualTo("Hello");
         }

Note : Tried adding a where clause "OR assert.name =~ ".assert."" but doesn't detect these asserts.

skpraveen
  • 183
  • 1
  • 5
  • 18

2 Answers2

1

It would be

"OR assert.name =~ ".*assert.*"" 

But it has the drawback that every method containing assert in name is marked. Note the stars after the dots.

Given that you want to use the provided "junit4:TestMethodWithoutAssertion" constraint, I would suggest the AssertJ version of the http://buschmais.github.io/jqassistant/doc/1.3.0/#junit4:AssertMethod concept:

<concept id="assertj:AssertMethod">
    <description>Labels all assertion methods declared by org.assertj.core.api.Assertions with "Assertj" and "Assert".</description>
    <cypher><![CDATA[
        MATCH
                (assertType:Type)-[:DECLARES]->(assertMethod)
            WHERE
            assertType.fqn = 'org.assertj.core.api.Assertions'
            and assertMethod.signature =~ '.*assertThat.*'
        SET
        assertMethod:Assertj:Assert
        RETURN
                assertMethod
        ]]></cypher>
</concept>

So your group definition now is as follows:

<group id="default">
    <includeConcept refId="assertj:AssertMethod" />
    <includeConstraint refId="junit4:TestMethodWithoutAssertion" />
</group>

Now your provided sample method is handled correctly.

Jens Nerche
  • 118
  • 8
  • Thanks for the reply. Was helpful. Will try this. However, the "OR assert.name =~ ".*assert.*"" didn't work. Appears like the "name" attribute is not available. – skpraveen Apr 27 '18 at 14:02
  • have one more related query https://stackoverflow.com/questions/50064438/jqassistant-rule-for-testmethods-with-lambda-expressions-and-consumers-asserts . Pls check if you have any thoughts. – skpraveen Apr 27 '18 at 14:22
  • assert has the label Method. These nodes have a name property. But not if the artifact (e.g. the AssertJ jar) is not scanned itself, the nodes only created due to other scanned artifacts. So in your context it may be that these nodes only have the signature property, thats's correct. – Jens Nerche Apr 28 '18 at 06:29
1

Have a look at the Spring PetClinic demo application: it provides a concept "assertj:AssertMethod" in assertj.adoc:

[[assertj:AssertMethod]]
[source,cypher,role=concept]
.Mark all assertThat methods of 'org.assertj.core.api.Assertions' with "AssertJ" and "Assert".
----
MATCH
  (assertType:Type)-[:DECLARES]->(assertMethod)
WHERE
  assertType.fqn = 'org.assertj.core.api.Assertions'
  and assertMethod.signature =~ '.* assertThat.*'
SET
  assertMethod:AssertJ:Assert
RETURN
  assertMethod
----

which is then referenced by a constraint in test.adoc:

[[test:TestMethodWithoutAssertion]]
[source,cypher,role=constraint,requiresConcepts="junit4:TestMethod,assertj:AssertMethod,spring-test-web:Assert"]
.All test methods must perform at least one assertion (within a call hierarchy of max. 3 steps).
----
MATCH
  (testType:Test:Type)-[:DECLARES]->(testMethod:Test:Method)
WHERE
  NOT (testMethod)-[:INVOKES*..3]->(:Method:Assert)
RETURN
  testType AS DeclaringType,
  testMethod AS Method
----
Dirk Mahler
  • 1,186
  • 1
  • 6
  • 7