티스토리 뷰

Java

[Java] 단위테스트 Spock Framework

snail voyager 2024. 6. 9. 22:43
728x90
반응형

Spock Framework

Groovy 언어로 작성된 테스트 프레임워크로, JVM 기반 언어(Java, Groovy 등)에서 유닛 테스트와 BDD(Behavior Driven Development)를 쉽게 작성할 수 있게 해줍니다. 

Spock은 간결하고 읽기 쉬운 문법과 강력한 기능을 제공하여 테스트 코드를 작성하고 유지보수하는 데 큰 도움을 줍니다.

 

  • 직관적인 문법: 테스트 코드는 인간이 읽기 쉬운 형식으로 작성됩니다.
  • 강력한 모킹 및 스텁 기능: 내장된 모킹 및 스텁 지원으로 간편하게 테스트 더블을 생성할 수 있습니다.
  • BDD 스타일의 테스트: given, when, then 블록을 사용하여 테스트 시나리오를 명확하게 작성할 수 있습니다.
  • 데이터 주도 테스트: 다양한 입력 데이터를 쉽게 테스트할 수 있는 데이터 드리븐 테스트를 지원합니다.

의존성 추가

plugins {
	...
	id 'groovy'	//groovy 추가
}

dependencies {
	testImplementation 'org.spockframework:spock-spring:2.3-groovy-4.0'
	testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0'
	testImplementation 'org.apache.groovy:groovy-all:4.0.20'
}


spring boot 3.1.4
java 17 
IntelliJ 2023.2.2 기준 spock-spring, spock-core 최신 버전 안됨
testImplementation 'org.spockframework:spock-spring:2.4-M4-groovy-4.0'
testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0'
testImplementation 'org.apache.groovy:groovy-all:4.0.22'

IntelliJ Gradle build 설정

Settings > Build > Gradle

Build and run using, Run test using 을 IntelliJ로 변경한다.

테스트 예제 정의

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }
}

기본 테스트

import spock.lang.Specification

class CalculatorSpec extends Specification {

    def calculator = new Calculator()

    def "addition should return the sum of two numbers"() {
        expect:
        calculator.add(2, 3) == 5
    }

    def "subtraction should return the difference of two numbers"() {
        expect:
        calculator.subtract(5, 2) == 3
    }
}

BDD 테스트

class CalculatorSpec extends Specification {

    def calculator = new Calculator()

    def "addition should return the sum of two numbers"() {
        given: "a calculator"
        // calculator 객체는 이미 선언되어 있음

        when: "two numbers are added"
        def result = calculator.add(2, 3)

        then: "the result should be the sum of the two numbers"
        result == 5
    }

    def "subtraction should return the difference of two numbers"() {
        given: "a calculator"
        // calculator 객체는 이미 선언되어 있음

        when: "one number is subtracted from another"
        def result = calculator.subtract(5, 2)

        then: "the result should be the difference of the two numbers"
        result == 3
    }
}

데이터 주도 테스트

class CalculatorSpec extends Specification {

    def calculator = new Calculator()

    def "addition should return the sum of two numbers"() {
        expect:
        calculator.add(a, b) == result

        where:
        a | b || result
        1 | 2 || 3
        3 | 3 || 6
        5 | 7 || 12
    }

    def "subtraction should return the difference of two numbers"() {
        expect:
        calculator.subtract(a, b) == result

        where:
        a | b || result
        5 | 2 || 3
        10 | 5 || 5
        9 | 4 || 5
    }
}

Mocking 

class UserService {
    UserRepository userRepository

    User getUserById(Long id) {
        userRepository.findById(id)
    }
}

interface UserRepository {
    User findById(Long id)
}

class UserServiceSpec extends Specification {

    def userRepository = Mock(UserRepository)
    def userService = new UserService(userRepository: userRepository)

    def "should return user by id"() {
        given:
        def user = new User(id: 1L, name: "John Doe")
        userRepository.findById(1L) >> user

        when:
        def result = userService.getUserById(1L)

        then:
        result == user
    }
}

then, expect 블록 차이

then 블록 : 주로 명시적이고 복잡한 검증을 수행할 때 사용됩니다. 보통 when 블록과 함께 사용되며, 테스트 대상의 동작을 검증합니다.

class CalculatorSpec extends Specification {

    def "addition should return the sum of two numbers"() {
        given: "a calculator"
        def calculator = new Calculator()

        when: "two numbers are added"
        def result = calculator.add(2, 3)

        then: "the result should be the sum of the two numbers"
        result == 5
        // 추가적인 검증도 가능
        result > 0
        result < 10
    }
}

expect 블록 : 단순한 입력과 출력에 대한 검증을 수행할 때 사용됩니다. 주로 given 블록과 함께 사용되며, 특정 조건이 참인지 검증하는 데 사용됩니다.

class CalculatorSpec extends Specification {

    def "addition should return the sum of two numbers"() {
        given: "a calculator"
        def calculator = new Calculator()

        expect: "the result should be the sum of the two numbers"
        calculator.add(2, 3) == 5
    }
}

assert 키워드

assert 키워드는 표현식이 참인지 확인하고, 거짓일 경우 AssertionError를 던집니다. 

assert 키워드는 Spock 테스트 코드에서 사용될 수 있지만, Spock의 expect나 then 블록을 사용하는 것이 더 일반적

import spock.lang.Specification

class CalculatorSpec extends Specification {

    def "addition should return the sum of two numbers"() {
        given: "a calculator"
        def calculator = new Calculator()

        when: "two numbers are added"
        def result = calculator.add(2, 3)

        then: "the result should be the sum of the two numbers"
        assert result == 5
        // 추가적인 assert
        assert result > 0
        assert result < 10
    }
}

assert 키워드 사용 시 주의사항

  • 디버깅: assert 키워드는 실패 시 기본적인 오류 메시지를 제공하지만, then이나 expect 블록을 사용하면 실패한 조건에 대해 더 자세한 오류 메시지를 얻을 수 있습니다.
  • 가독성: Spock의 BDD 스타일 블록(given, when, then, expect)은 테스트 코드의 가독성을 높여줍니다. 따라서 가능하면 Spock 블록을 사용하여 검증을 수행하는 것이 좋습니다.

 

 

 

 

 

 

 

728x90
반응형
반응형
300x250