1

I have written two test classes (CryptUtilTest1.groovy, CryptUtilTest2.groovy) for the same tool class method. I mock StringImplUtils.emptyIfBlank method in CryptUtilTest2.groovy. When the two test classes are executed separately, the test classes can be executed normally. However, when the two test cases are executed together, the second test class sometimes has the following error:

enter image description here

> Task :CallServer:compileJava UP-TO-DATE
> Task :CallServer:compileGroovy NO-SOURCE
> Task :CallServer:processResources UP-TO-DATE
> Task :CallServer:classes UP-TO-DATE
> Task :CallServer:compileTestJava NO-SOURCE
> Task :CallServer:compileTestGroovy
> Task :CallServer:processTestResources UP-TO-DATE
> Task :CallServer:testClasses
> Task :CallServer:test
[INFO] TestableMock start at E:\isouceWork\VRBT_RCPA_V100R001C10\JAVA_CODE\CallServer



Misplaced or misused argument matcher detected here:

-> at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(any());
    verify(mock).someMethod(contains("foo"))

This message may appear after an NullPointerException if the last matcher is returning an object 
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
    when(mock.get(any())); // bad use, will raise NPE
    when(mock.get(anyInt())); // correct usage use

Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Misplaced or misused argument matcher detected here:

-> at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(any());
    verify(mock).someMethod(contains("foo"))

This message may appear after an NullPointerException if the last matcher is returning an object 
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
    when(mock.get(any())); // bad use, will raise NPE
    when(mock.get(anyInt())); // correct usage use

Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.

    at com.huawei.callserver.utils.CryptUtilTest2.test(CryptUtilTest2.groovy:22)
    Suppressed: java.lang.NullPointerException: Cannot invoke method close() on null object
        at org.codehaus.groovy.runtime.NullObject.invokeMethod(NullObject.java:91)
        at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:44)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.NullCallSite.call(NullCallSite.java:34)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:130)
        at com.huawei.callserver.utils.CryptUtilTest2.$spock_feature_0_0(CryptUtilTest2.groovy:29)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.spockframework.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:198)
        at org.spockframework.runtime.model.MethodInfo.lambda$new$0(MethodInfo.java:47)
        at org.spockframework.runtime.model.MethodInfo.invoke(MethodInfo.java:148)
        at org.spockframework.runtime.PlatformSpecRunner.invokeRaw(PlatformSpecRunner.java:409)
        at org.spockframework.runtime.PlatformSpecRunner.invoke(PlatformSpecRunner.java:392)
        at org.spockframework.runtime.PlatformSpecRunner.runFeatureMethod(PlatformSpecRunner.java:326)
        at org.spockframework.runtime.IterationNode.execute(IterationNode.java:48)
        at org.spockframework.runtime.SimpleFeatureNode.execute(SimpleFeatureNode.java:58)
        at org.spockframework.runtime.SimpleFeatureNode.execute(SimpleFeatureNode.java:15)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
        at org.spockframework.runtime.SpockNode.sneakyInvoke(SpockNode.java:40)
        at org.spockframework.runtime.IterationNode.lambda$around$0(IterationNode.java:63)
        at org.spockframework.runtime.PlatformSpecRunner.lambda$createMethodInfoForDoRunIteration$5(PlatformSpecRunner.java:238)
        at org.spockframework.runtime.model.MethodInfo.invoke(MethodInfo.java:148)
        at org.spockframework.runtime.PlatformSpecRunner.invokeRaw(PlatformSpecRunner.java:409)
        at org.spockframework.runtime.PlatformSpecRunner.invoke(PlatformSpecRunner.java:392)
        at org.spockframework.runtime.PlatformSpecRunner.runIteration(PlatformSpecRunner.java:220)
        at org.spockframework.runtime.IterationNode.around(IterationNode.java:63)
        at org.spockframework.runtime.SimpleFeatureNode.lambda$around$0(SimpleFeatureNode.java:52)
        at org.spockframework.runtime.SpockNode.sneakyInvoke(SpockNode.java:40)
        at org.spockframework.runtime.FeatureNode.lambda$around$0(FeatureNode.java:29)
        at org.spockframework.runtime.PlatformSpecRunner.lambda$createMethodInfoForDoRunFeature$4(PlatformSpecRunner.java:201)
        at org.spockframework.runtime.model.MethodInfo.invoke(MethodInfo.java:148)
        at org.spockframework.runtime.PlatformSpecRunner.invokeRaw(PlatformSpecRunner.java:409)
        at org.spockframework.runtime.PlatformSpecRunner.invoke(PlatformSpecRunner.java:392)
        at org.spockframework.runtime.PlatformSpecRunner.runFeature(PlatformSpecRunner.java:194)
        at org.spockframework.runtime.FeatureNode.around(FeatureNode.java:29)
        at org.spockframework.runtime.SimpleFeatureNode.around(SimpleFeatureNode.java:52)
        at org.spockframework.runtime.SimpleFeatureNode.around(SimpleFeatureNode.java:15)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
        at java.util.ArrayList.forEach(ArrayList.java:1257)
        at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
        at org.spockframework.runtime.SpockNode.sneakyInvoke(SpockNode.java:40)
        at org.spockframework.runtime.SpecNode.lambda$around$0(SpecNode.java:63)
        at org.spockframework.runtime.PlatformSpecRunner.lambda$createMethodInfoForDoRunSpec$0(PlatformSpecRunner.java:61)
        at org.spockframework.runtime.model.MethodInfo.invoke(MethodInfo.java:148)
        at org.spockframework.runtime.PlatformSpecRunner.invokeRaw(PlatformSpecRunner.java:409)
        at org.spockframework.runtime.PlatformSpecRunner.invoke(PlatformSpecRunner.java:392)
        at org.spockframework.runtime.PlatformSpecRunner.runSpec(PlatformSpecRunner.java:55)
        at org.spockframework.runtime.SpecNode.around(SpecNode.java:63)
        at org.spockframework.runtime.SpecNode.around(SpecNode.java:11)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
        at java.util.ArrayList.forEach(ArrayList.java:1257)
        at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
        at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
        at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
        at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
        at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
        at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
        at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
        at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
        at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
        at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
        at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
        at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
        at com.sun.proxy.$Proxy2.stop(Unknown Source)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
        at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
        at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
        at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)


Condition not satisfied:

"123" == CryptUtil.test("123")
      |  |         |
      |  |         null
      |  class com.huawei.callserver.utils.CryptUtil
      false

Condition not satisfied:

"123" == CryptUtil.test("123")
      |  |         |
      |  |         null
      |  class com.huawei.callserver.utils.CryptUtil
      false

    at com.huawei.callserver.utils.CryptUtilTest2.test1(CryptUtilTest2.groovy:35)


CryptUtilTest2 > test FAILED
    org.mockito.exceptions.misusing.InvalidUseOfMatchersException at CryptUtilTest2.groovy:22
CryptUtilTest2 > test1 FAILED
    org.spockframework.runtime.SpockComparisonFailure at CryptUtilTest2.groovy:35
7 tests completed, 2 failed
> Task :CallServer:test FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':CallServer:test'.
> There were failing tests. See the report at: file:///E:/isouceWork/VRBT_RCPA_V100R001C10/JAVA_CODE/CallServer/build/reports/tests/test/index.html
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org

Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.

You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

See https://docs.gradle.org/7.2/userguide/command_line_interface.html#sec:command_line_warnings
BUILD FAILED in 17s
5 actionable tasks: 2 executed, 3 up-to-date

the separate result of two test class was shown as below:

CryptUtilTest1

enter image description here

CryptUtilTest2

enter image description here

gradle.build

testImplementation 'org.codehaus.groovy:groovy-all:3.0.7'
testImplementation group: 'org.spockframework', name: 'spock-core', version: '2.0-groovy-3.0'
testImplementation group: 'org.spockframework', name: 'spock-spring', version: '2.0-groovy-3.0'
testImplementation group: 'org.mockito', name: 'mockito-inline', version: '4.9.0'

my test code:

class CryptUtilTest1 extends Specification {

    def "decrypt"() {
        when:
        def decryptStr = CryptUtil.decrypt("d2NjX2NyeXB0ATQxNDU1MzVGNDc0MzREOzMwMzE0NTMxMzAzNDQxMzYzODQzMzI0NDQzMzA0NjQyMzU0MTQ1NDIzNjQ2MzA0NTMwMzUzNDM2Mzc0NTQyNDE0MjM5MzQ0MjM4MzEzNTMxNDYzNTM0MzYzMDMxNDEzNDMwNDI0NDQxMzk0Mjs7MzEzMDMwMzA7QTk1MjBGNjVBNjg3MzE4MkZFNUExNkZDMDI5MDg5N0Q7QkQ5NzlDQUQ1MzkyQzdEMUJFQ0VFNEVENUNENDlGNDE7MzgzMDM1Mzg2MTY2MzMzMzJEMzQzNzYyMzAyRDM0MzQzNDM0MkQzODYxMzAzMjJENjQzNjM3NjI2NDYxMzg2NjMxNjE2NTYxOw==")
        then:
        decryptStr == "12345"
    }

    def "encryptAES256"() {
        when:
        def encryptStr = CryptUtil.encryptAES256(Mockito.anyString())
        then:
        encryptStr != ""
    }

    def "encryptByMD5"() {
        when:
        def encryptByMD5 = CryptUtil.encryptByMD5("133")

        then:
        encryptByMD5 == "9fc3d7152ba9336a670e36d0ed79bc43"
    }

    def "encryptByMD5Telecom"() {
        when:
        def encryptByMD5Telecom = CryptUtil.encryptByMD5Telecom("133")

        then:
        encryptByMD5Telecom == "1efb11cd74b5a654c8c6727736ea4ea0"
    }

    def "test"() {
        when:
        def testRes = CryptUtil.test("133")
        then:
        testRes == "133"
    }


}
class CryptUtilTest2 extends Specification {


    def test() {
        given:
        var mockedStatic = Mockito.mockStatic(StringImplUtils.class)
        mockedStatic.when(() -> StringImplUtils.emptyIfBlank("123")).thenReturn("aaaa")

        expect:
        "aaaa" == CryptUtil.test("123")

        cleanup:
        mockedStatic.close()

    }

    def test1() {
        expect:
        "123" == CryptUtil.test("123")
    }


}
public final class CryptUtil {

    private static final Crypter CRYPTER = CrypterFactory.getCrypter();

    private CryptUtil() {
    }

    public static String decrypt(String cipherText) {
        return CRYPTER.decrypt(cipherText);
    }


    public static String encryptByMD5(String plainText) throws NoSuchAlgorithmException {
        byte[] secretBytes = null;
        secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes(StandardCharsets.UTF_8));
        String md5code = new BigInteger(1, secretBytes).toString(16);
        int len = md5code.length();
        for (int i = 0; i < 32 - len; i++) {
            md5code = "0" + md5code;
        }
        return md5code;
    }

    public static String encryptByMD5Telecom(String str) throws NoSuchAlgorithmException {
        byte[] res = str.getBytes(Charset.forName("UTF-8"));
        MessageDigest digest = MessageDigest.getInstance("MD5");
        byte[] result = digest.digest(res);
        for (int i = 0; i < result.length; i++) {
            digest.update(result[i]);
        }
        byte[] hash = digest.digest();
        StringBuffer resultStr = new StringBuffer("");

        for (int i = 0; i < hash.length; i++) {
            int hex = hash[i] & 0xFF;
            if (hex < 16) {
                resultStr.append('0');
            }
            resultStr.append((Integer.toString(hex, 16)).toLowerCase(Locale.getDefault()));
        }
        return resultStr.toString();
    }

    public static String encryptAES256(String text) {
        return CRYPTER.encrypt(text);
    }

    public static String test(String text) {
        String testStr = StringImplUtils.emptyIfBlank(text);
        return testStr;
    }

When I use spock1.*+powermock to test, this probability error does not occur.

kriegaex
  • 63,017
  • 15
  • 111
  • 202
ppanda2021
  • 15
  • 6
  • This is a Mockito rather than a Spock question. Besides, why don't you do yourself a favour and refactor your tool class with ugly static methods to one you can instantiate, singleton or not? Then you do not need any special tools like Mockito or PowerMock anymore and can just use Spock mocks. If code is difficult to test, it is a sign that you should fix your application design rathen than look for fancier tools. Test automation is a design tool, please use it as such. – kriegaex Dec 02 '22 at 15:03
  • Maybe you are right. Singletons are easier to test, but sometimes static methods cannot be avoided because of performance requirements. I will continue to go to Mockito to get the answers to the above questions. – ppanda2021 Dec 05 '22 at 01:48
  • What kind of performance requirements could that be? I never met a case in which static methods were necessary due to performance reasons. A singleton instance maybe, but static methods? No. Anyway, back to your problem: That the tests pass in isolation but not when run together tells you something: Either there is a problem with parallel execution (if you use that in Spock at all), or you might not be cleaning up a fixture (resource used in the test) correctly, bleeding context over into the other test, violating its assumptions. – kriegaex Dec 05 '22 at 08:22

1 Answers1

0

I can reproduce the problem when executing the tests together in this order:

  1. CryptUtilTest1
  2. CryptUtilTest2

In the reverse order, the problem does not occur. The problem also goes away if you refrain from using Mockito.anyString() in the first test, which is not really a Mockito test anyway. That method returns "" anyway, so you can just replace it by "" or "dummy" in your first test. Then the tests pass. Mockito's any*() methods are meant to be used inside mockito matcher expressions, e.g. something like verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));.

kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • Thank you very much for your answer.But you didn't explain why running any test class individually, it can run successfully even if using Mockito.anyString(). In addition, use Mockito.anyString() in the test case because the output of encryptAES256 method is not a fixed value – ppanda2021 Dec 06 '22 at 07:32
  • When you proposed using a singleton, I wrote the test code for the mock singleton with junit5+mockito4.* , but there were still some strange problems.[issue](https://stackoverflow.com/questions/74699357/use-cases-interaction-when-using-mockito4-to-mock-singleton) – ppanda2021 Dec 06 '22 at 08:28
  • I did not debug into Mockito, but my assumptiuon is that calling `Mockito.anyString()` outside of a mocking/stubbing situation leaves Mockito in an inconsistent state which disturbs subsequent tests. It is simply a user error to do that. That inconsistent state does not matter in a single test run, because the JVM is closed after the test and no subsequent test uses Mockito anymore. – kriegaex Dec 06 '22 at 09:17
  • With regard to the singleton, you do not need Mockito anymore if you use Spock mocks. Why did you switch to JUnit 5? But even with JUnit 5, you should not call `any*()` falsely, see above. It is not a Spock or JUnit problem, but a Mockito usage problem. I have not looked into the other question yet, maybe I can after work. Usually I avoid JUnit 5 and Mockito, I simply use Spock. – kriegaex Dec 06 '22 at 09:21
  • Thanks for your reply. The spock cannot directly mock a singleton.But it can be mocked in some way, referring to your answer to this question .[links](https://stackoverflow.com/questions/51136630/mocking-a-singleton-in-groovy) – ppanda2021 Dec 06 '22 at 10:26