[JAVA] [Spring Boot] Ich bin auf einen Methodenaufruf-Count-Test gestoßen (Spock-Framework)

Einführung

Das erste Jahr der neuen Absolventen ist fast vorbei. Während ich Spocks Framework benutzte, stieß ich auf verschiedene Arten, Mockito und Spock zu verspotten, also machte ich ein Memorandum und teilte es ähnlichen Leuten mit. Es wäre besser, eine Instanz in der tatsächlichen Situation zu erstellen, ohne den hier beschriebenen Code zu verspotten, aber es ist nur ein Beispiel ...

Umgebung

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	// https://mvnrepository.com/artifact/org.spockframework/spock-core
	testCompile group: 'org.spockframework', name: 'spock-core', version: '1.3-groovy-2.5'
	// https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all
	compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.5.6', ext: 'pom'
}

Quellcode

Es wird auf GitHub veröffentlicht.

Prüfung

Überprüfen Sie die Anzahl der normalen Methodenaufrufe

Mockito Verwenden Sie when --then Return, um den vom Mock zurückgegebenen Wert festzulegen. Da spockComponent1Factory das Ziel der Injektion ist, wird "initMocks" mit "setup" und die Anmerkung "InjectMocks" hinzugefügt. Es scheint, dass Sie die Anzahl überprüfen können, indem Sie "wahr" in den Teil "verifizieren" schreiben, aber es fühlt sich sehr seltsam an ...

SpockComponent1FactoryTest.groovy


    @InjectMocks
    SpockComponent1Factory spockComponent1Factory

    @Mock
    SpockComponent2Factory spockComponent2Factory

    @Mock
    SpockComponent2 spockComponent2

    @Mock
    SpockComponent3 spockComponent3

    @Mock
    SpockComponent4 spockComponent4

    def setup() {
        initMocks(this)
    }

    def "GetValueFromSpockComponent4 -Überprüfen Sie die Anzahl der Anrufe"() {
        given:
        when(spockComponent2Factory.create(any(Integer.class))).thenReturn(spockComponent2)
        when(spockComponent2.getSpockComponent3()).thenReturn(spockComponent3)
        when(spockComponent3.getSpockComponent4()).thenReturn(spockComponent4)

        when:
        spockComponent1Factory.getValueFromSpockComponent4(0)

        then:
        verify(spockComponent2Factory, times(1)).create(any(Integer.class)) || true
    }

Verwenden Sie RETURN_DEEP_STUBS, um verschachtelte Instanzen zu verspotten. Durch Umschreiben des obigen Tests kann wie folgt geschrieben werden.

SpockComponent1FactoryTestAlt.groovy


    @InjectMocks
    SpockComponent1Factory spockComponent1Factory

    @Mock
    SpockComponent2Factory spockComponent2Factory

    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    SpockComponent2 spockComponent2

    @Mock
    SpockComponent4 spockComponent4

    def setup() {
        initMocks(this)
    }

    def "getValueFromSpockComponent -Unterbrechung der Anrufzählungsprüfung"() {
        given:
        when(spockComponent2Factory.create(any(Integer.class))).thenReturn(spockComponent2)
        when(spockComponent2.getSpockComponent3().getSpockComponent4()).thenReturn(spockComponent4)

        when:
        spockComponent1Factory.getValueFromSpockComponent4(0)

        then:
        verify(spockComponent2Factory, times(1)).create(any(Integer.class)) || true
    }

Spock Ein ähnlicher in Spock geschriebener Test sieht folgendermaßen aus: Wenn Sie die Anzahl der Ausführungen überprüfen möchten, scheint der Test nicht bestanden zu werden, es sei denn, Sie verspotten und stubben gleichzeitig in der "dann" -Klausel. Übrigens, wenn Sie in Spock das in "setup" festgelegte Verhalten mit einzelnen Testfällen überschreiben möchten, müssen Sie dies anscheinend in der "then" -Klausel tun. (Referenz: Stackoverflow-Official Document)

SpockComponent1FactoryTestSpock.groovy


    SpockComponent1Factory spockComponent1Factory

    SpockComponent2Factory spockComponent2Factory

    SpockComponent2 spockComponent2

    SpockComponent3 spockComponent3

    SpockComponent4 spockComponent4

    def setup() {
        spockComponent2Factory = Mock(SpockComponent2Factory.class)
        spockComponent2 = Mock(SpockComponent2.class)
        spockComponent3 = Mock(SpockComponent3.class)
        spockComponent4 = Mock(SpockComponent4.class)
    }

    def "GetValueFromSpockComponent4 -Anrufzählungsprüfung fehlgeschlagen"() {
        given:
        spockComponent3.getSpockComponent4() >> spockComponent4
        spockComponent2.getSpockComponent3() >> spockComponent3
        spockComponent2Factory.create(_ as Integer) >> spockComponent2

        when:
        spockComponent1Factory = new SpockComponent1Factory(spockComponent2Factory)
        spockComponent1Factory.getValueFromSpockComponent4(0)

        then:
        1 * spockComponent2Factory.create(_ as Integer)
    }

    def "GetValueFromSpockComponent4 -Erfolgreiche Überprüfung der Anrufanzahl"() {
        given:
        spockComponent3.getSpockComponent4() >> spockComponent4
        spockComponent2.getSpockComponent3() >> spockComponent3

        when:
        spockComponent1Factory = new SpockComponent1Factory(spockComponent2Factory)
        spockComponent1Factory.getValueFromSpockComponent4(0)

        then:
        1 * spockComponent2Factory.create(_ as Integer) >> spockComponent2
    }

Spock braucht auch etwas Einfallsreichtum, um verschachtelte Instanzen zu verspotten. Weniger als.

SpockComponent1FactoryTestSpockAlt.groovy


    SpockComponent1Factory spockComponent1Factory

    SpockComponent2Factory spockComponent2Factory

    SpockComponent2 spockComponent2

    SpockComponent4 spockComponent4

    def setup() {
        spockComponent2Factory = Mock(SpockComponent2Factory.class)
        spockComponent2 = Mock(SpockComponent2.class)
        spockComponent4 = Mock(SpockComponent4.class)
    }

    def "GetValueFromSpockComponent4 -Unterbrechung der Anrufzählungsprüfung"() {
        given:
        spockComponent2.getSpockComponent3() >> {
            Mock(SpockComponent3.class) {
                getSpockComponent4() >> spockComponent4
            }
        }

        when:
        spockComponent1Factory = new SpockComponent1Factory(spockComponent2Factory)
        spockComponent1Factory.getValueFromSpockComponent4(0)

        then:
        1 * spockComponent2Factory.create(_ as Integer) >> spockComponent2
    }

Überprüfen Sie die Anzahl der Aufrufe von Methoden, die null als Argument verwenden

Im Implementierungscode wird null direkt in die Methode eingefügt, die das Argument String verwendet.

SpockComponent1Factory.java


    public void nullArgumentMethodCall() {
        spockComponent2Factory.nullArgumentMethodCalled(null);
    }

Mockito Als ich versuchte, mit "any ()" zu prüfen, konnte es nicht überprüft werden, also habe ich "nullable ()" verwendet.

SpockComponent1FactoryTest.groovy


    @InjectMocks
    SpockComponent1Factory spockComponent1Factory

    @Mock
    SpockComponent2Factory spockComponent2Factory

    @Mock
    SpockComponent2 spockComponent2

    @Mock
    SpockComponent3 spockComponent3

    @Mock
    SpockComponent4 spockComponent4

    def setup() {
        initMocks(this)
    }

    def "NullArgumentMethodCall -Anrufzählungsprüfung fehlgeschlagen"() {
        when:
        spockComponent1Factory.nullArgumentMethodCall()

        then:
        verify(spockComponent2Factory, times(1)).nullArgumentMethodCalled(any(String.class)) || true
    }

    def "NullArgumentMethodCall -Erfolgreiche Überprüfung der Anrufanzahl"() {
        when:
        spockComponent1Factory.nullArgumentMethodCall()

        then:
        verify(spockComponent2Factory, times(1)).nullArgumentMethodCalled(nullable(String.class)) || true
    }

Spock Die Spock-Seite funktionierte ohne Probleme.

SpockComponent1FactoryTestSpock.groovy


    SpockComponent1Factory spockComponent1Factory

    SpockComponent2Factory spockComponent2Factory

    SpockComponent2 spockComponent2

    SpockComponent3 spockComponent3

    SpockComponent4 spockComponent4

    def setup() {
        spockComponent2Factory = Mock(SpockComponent2Factory.class)
        spockComponent2 = Mock(SpockComponent2.class)
        spockComponent3 = Mock(SpockComponent3.class)
        spockComponent4 = Mock(SpockComponent4.class)
    }

    def "NullArgumentMethodCall -Überprüfen Sie die Anzahl der Anrufe"() {
        when:
        spockComponent1Factory = new SpockComponent1Factory(spockComponent2Factory)
        spockComponent1Factory.nullArgumentMethodCall()

        then:
        spockComponent2Factory.nullArgumentMethodCalled(_ as String)
    }
}

abschließend

Wie eingangs erwähnt, kann es möglich sein, den Testcode durch das Erstellen einer Instanz besser lesbar zu machen als durch Verspotten. Daher scheint es besser, ihn während des Denkens zu schreiben (auch als Gebot an sich selbst).

Recommended Posts

[Spring Boot] Ich bin auf einen Methodenaufruf-Count-Test gestoßen (Spock-Framework)
Ich habe jetzt einen Test mit Spring Boot + JUnit 5 geschrieben
Ich möchte eine Methode aufrufen und die Nummer zählen
Machen Sie System.out Mock mit dem Spock Test Framework
Ich möchte eine Methode einer anderen Klasse aufrufen
So schreiben Sie einen Komponententest für Spring Boot 2
[JUnit 5-kompatibel] Schreiben Sie einen Test mit JUnit 5 mit Spring Boot 2.2, 2.3
[JUnit 5] Schreiben Sie einen Validierungstest mit Spring Boot! [Parametrisierungstest]
[Anfänger] Ich bin auf ein Projekt mit Rails6 gestoßen
Worauf ich beim ActiveModel :: Serializer-Test gestoßen bin
Ich habe Spring Boot seit einem Monat nicht mehr verstanden
Einführung von Spring Boot2, einem Java-Framework für die Webentwicklung (für Anfänger)
Ich habe mit Spring Boot ein einfaches MVC-Beispielsystem erstellt
Memo zur Spring Boot Controller-Methode
Ich habe das Spring Boot-Einführungshandbuch [Erstellen eines RESTful-Webdiensts] ausprobiert.
Ich habe ein einfaches Suchformular mit Spring Boot + GitHub Search API erstellt.
Beispielcode zum Testen eines Spring Boot-Controllers mit MockMvc
Spring Boot Erste Schritte [Konsumieren eines RESTful-Webdienstes]
Schreiben wir einen Testcode für die Anmeldefunktion mit Spring Boot