Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2023.9.3 일일 학습 기록 - JUnit5 기본 사용방법 #14

Open
ChanJun-Park opened this issue Sep 3, 2023 · 0 comments
Open

2023.9.3 일일 학습 기록 - JUnit5 기본 사용방법 #14

ChanJun-Park opened this issue Sep 3, 2023 · 0 comments

Comments

@ChanJun-Park
Copy link
Owner

JUnit Basics

JUnit 는 테스트 프레임워크이다. 테스트 프레임 워크는 테스트 작성에 필요한 api 들을 제공하고, 테스트를 실행하며, 성공한 테스트와 실패한 테스트들의 리포트를 제공해주는 역할을 한다.

안드로이드 스튜디오에서는 테스트 프레임워크로 JUnit 을 자동으로 세팅한다.

JUnit5

안드로이드 스튜디오에서 자동으로 설정하는 테스트 프레임워크는 JUnit4 이다. 현재는 JUnit5 가 나와서 더 많은 테스트 기능을 제공하고 있고, 유닛테스트를 작성할때 이러한 기능을 사용하는 것이 도움이 되기 때문에 JUnit5 를 사용하는 것이 좋다.

JUnit5 를 사용하기 위해서는 다음과 같은 의존성 추가와 그레이들 플러그인을 추가할 필요가 있다.

plugins {
	id 'de.mannodermaus.android-junit5' version "1.9.3.0"
}
dependencies {
	testImplementation "org.junit.jupiter:junit-jupiter-api:5.9.3"
	testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.9.3"
	testImplementation "org.junit.jupiter:junit-jupiter-params:5.9.3"
}

AssertK

assertion 을 좀 더 가독성 있게 작성할 수 있도록 도와주는 라이브러리이다. assertion 이란 테스트를 하고자 하는 기능이 정확한 동작을 수행했는지를 검증하는 api 이다.

다음 코틀린 전용 assertion 라이브러리를 사용하면 도움이 된다.

testImplementation "com.willowtreeapps.assertk:assertk:0.26.1"
import assertk.assertThat
import assertk.assertions.isEqualTo
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

class ExampleUnitTest {

    @BeforeEach // 각각의 테스트 메소드가 실행되기 전에 수행됨, 주로 새로운 인스턴스나 상태를 생성하기 위해 사용
    fun setUp() {

    }

    @AfterEach  // 각각의 테스트 메소드가 종료된 후 실행됨. 자원 정리같은 작업에 사용됨.
    fun tearDown() {

    }

    @Test
    fun addition_isCorrect() {
//        assertEquals(4, 2 + 2)
        assertThat(2 + 2).isEqualTo(4) // assertK 를 통해 가독성 향상
    }
}

Repeated tests

JUnit5 에서는 @RepeatedTest 어노테이션을 통해서 테스트를 여러번 수행할 수 있다. 동시성 프로그래밍을 하다보면 스레드 실행 순서에 따라서 레이스 컨디션 등의 문제가 간헐적으로 발생해 기능이 동작하거나 동작하지 않는 현상이 있을 수 있다. 이때 @RepeatedTest 를 통해서 여러번 기능을 수행해봄으로써 동시성 문제가 개선되었는지를 확인할 수 있다.

@RepeatedTest(value = 100)
fun `Add Product with negative quantity, throw Exception`() {
	// Given
	val product = Product(
		id = 0,
		name = "Ice cream",
		price = 5.0
	)
	assertFailure {
		shoppingCart.addProduct(product, -4)
	}
}

Parameterized tests

JUnit5 에서는 다양한 파라미터들을 이용해서 테스트를 여러번 수행할 수 있게 해준다.

@ParameterizedTest  // 테스트에 파라미터를 선언할 수 있게 해준다.
@ValueSource(       // 테스트에 어떤 파라미터를 넣을것인지 선언
	ints = [1, 2, 3, 4, 5]
)
fun `Add Multiple product, total count is correct`(quantity: Int) {
	// Given
	val product = Product(
		id = 0,
		name = "Ice cream",
		price = 5.0
	)
	shoppingCart.addProduct(product, quantity)

	// When
	val totalCost = shoppingCart.getTotalCost()

	// Then
	assertThat(totalCost).isEqualTo(quantity * 5.0)
}

다음과 같이 예상 결과 값을 함께 파라미터로 전달해줄 수도 있다.

@ParameterizedTest
@CsvSource(
	"0,0.0",
	"1,5.0",
	"2,10.0",
	"5,25.0",
	"6,30.0",
)
fun `Add Multiple product, total count is correct`(
	quantity: Int,
	expected: Double
) {
	// Given
	val product = Product(
		id = 0,
		name = "Ice cream",
		price = 5.0
	)
	shoppingCart.addProduct(product, quantity)

	// When
	val totalCost = shoppingCart.getTotalCost()

	// Then
	assertThat(totalCost).isEqualTo(expected)
}

How to test private functions?

private 접근자를 가지고 있는 메소드는 일반적으로 테스트 코드에서 접근이 불가능하다. @OpenForTesting 이라는 어노테이션을 붙이고 private 접근 제한자를 떼서 사용할 수도 있지만 권장되는 방법이 아니다.

대신 private 접근자를 사용하고 있는 메소드를 테스트 함으로써 간접적으로 private function 을 테스트 할 수 있다.

@Test
fun `Add invalid products, getTotalCost is zero`() {
    // Given
    val product = Product(
        id = 123,
        name = "Ice cream",
        price = 5.0
    )

    // When
    cart.addProduct(product, 5)

    // Then
    val totalCost = cart.getTotalCost()
    assertThat(totalCost).isEqualTo(0.0)
}

HomeWork

JUnit5 에서 List 를 테스트 인자로 전달하는 방법

[JUnit 5: Using Lists as an Argument for Parameterized Tests – Felix Seifert](https://blog.felix-seifert.com/junit-5-parameterized-tests-using-lists-as-argument/#)

JUnit5 에서는 @ParameterizedTest 라는 어노테이션을 이용해서 테스트 함수에 인자를 전달할 수 있다. @ParameterizedTest 를 이용할때는 반드시 테스트 함수에 전달할 인자를 제공해주는 Source 를 선언해야한다.

가장 간단한 형태의 Source 는 @ValueSource 이다.

@ParameterizedTest  // 테스트에 파라미터를 선언할 수 있게 해준다.
@ValueSource(       // 테스트에 어떤 파라미터를 넣을것인지 선언
	ints = [1, 2, 3, 4, 5]
)
fun `Add Multiple product, total count is correct`(quantity: Int) {
	// Given
	val product = Product(
		id = 0,
		name = "Ice cream",
		price = 5.0
	)
	shoppingCart.addProduct(product, quantity)

	// When
	val totalCost = shoppingCart.getTotalCost()

	// Then
	assertThat(totalCost).isEqualTo(quantity * 5.0)
}

결과값도 함께 전달하고 싶다면 @CsvSource 를 이용할 수 있다.

@ParameterizedTest
@CsvSource(
	"0,0.0", // 콤마로 구분된 2가지 인자를 테스트 함수에 전달
	"1,5.0",
	"2,10.0",
	"5,25.0",
	"6,30.0",
)
fun `Add Multiple product, total count is correct`(
	quantity: Int,
	expected: Double
) {
	// Given
	val product = Product(
		id = 0,
		name = "Ice cream",
		price = 5.0
	)
	shoppingCart.addProduct(product, quantity)

	// When
	val totalCost = shoppingCart.getTotalCost()

	// Then
	assertThat(totalCost).isEqualTo(expected)
}

인자를 생성하는 팩토리 메소드를 이용해서 동적으로 인자들을 생성하고 싶다면 @MethodSource 를 이용할 수 있다.

@ParameterizedTest
@MethodSource(
    "createArguments" // 인자를 생성하는 팩토리 메소드 이름을 전달
)
fun `params test`(param1: Int, param2: Int, param3: Int) {
    assertThat(param1 + param2).isEqualTo(param3)
}

private fun createArguments(): Stream<Arguments> { // 여러개의 인자를 생성하는 경우 Stream<Arguments>
    return Stream.of(                              // 한개의 인자만 생성하면 되는 경우 Stream<인자 타입>
        Arguments.of(1, 2, 3),
        Arguments.of(1, 1, 2),
        Arguments.of(1, 5, 6),
    )
}

@ParameterizedTest
@MethodSource(
    "createListArguments" // 인자를 생성하는 팩토리 메소드 이름을 전달
)
fun `list params test`(listParam: List<Int>, param2: Int) {
    assertThat(listParam.sum()).isEqualTo(param2)
}

private fun createListArguments(): Stream<Arguments> {
    return Stream.of(
        Arguments.of(listOf(1, 2, 3), 6),
        Arguments.of(listOf(1, 2, 4), 7),
    )
}
@ChanJun-Park ChanJun-Park changed the title 2023.9.3 일일 학습 기록 2023.9.3 일일 학습 기록 - JUnit5 기본 사용방법 Sep 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant