통합테스트는 주로 테스트하고자 하는 코드를 다른 의존관계와 연동이 잘 되는지를 테스트하는데 사용됩니다. 각각의 단위 테스트들이 완료된 모듈간에 연동을 테스트하거나 만든 시스템과 외부시스템과의 연동테스트 등이 통합테스트입니다.
주로 다음과 같은 기능을 제공합니다.
단일 jar파일 (모노리틱 아키텍쳐)
확장성이 떨어지는 문제 존재
JUnit 5의 3개의 모듈
JVM 상에 테스팅 프레임워크를 런칭하기 위한 근간을 제공합니다. 테스트를 발견하고 테스트 계획을 생성하는 TestEngine 인터페이스를 가지고 있고 TestEngine을 통해서 테스트를 발경하고 , 실행하고 , 결과를 보고합니다.
TestEnaine의 실제 구현체는 별도 모듈입니다. 모듈 중 하나가 jupiter-engine입니다. 이 모듈은 jupiter-api를 사용해서 작성한 테스트 코드를 발견하고 실행합니다. Jupiter API는 JUnit 5에 새롭게 추가된 테스트 코드용 API로서, 개발자는 Jupiter API를 사용해서 테스트 코드를 작성할 수 있습니다.
기존에 JUnit4. 버전으로 작성한 테스트 코드를 실행할 때에는 vintage-engine 모듈을 사용합니다.
import org.junit.jupiter.api.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
// FixedAmountVoucerTest가 곧 SUT
// 안에 있는 메소드가 MUT가 됩니다.
class FixedAmountVoucherTest {
private static final Logger logger = LoggerFactory.getLogger(FixedAmountVoucherTest.class);
@BeforeAll
static void setup() {
logger.info("@BeforeAll - run once");
}
@BeforeEach
void init() {
logger.info("@BeforeEach - run before each test method");
}
@Test
@DisplayName("기본적인 assertEqual 테스트😀 ")
void name() {
assertEquals(2, 1 + 1);
}
@Test
@DisplayName("주어진 금액만큼 할인을 해야한다.")
void testdiscount() {
var sut = new FixedAmountVoucher(UUID.randomUUID(), 100);
assertEquals(900, sut.discount(1000));
}
@Test
@DisplayName("디스카운트 된 금액은 마이너스가 될 수 없다.")
void testMinusDiscountAmount() {
var sut = new FixedAmountVoucher(UUID.randomUUID(), 1000);
assertEquals(0, sut.discount(900));
}
@Test
@DisplayName("할인 금액은 마이너스가 될 수 없다.")
void testWithMinus() {
assertThrows(IllegalArgumentException.class, () -> new FixedAmountVoucher(UUID.randomUUID(), -100));
}
@Test
@DisplayName("유효한 할인 금액으로만 생성할 수 있다.")
void testVoucherCreation() {
assertAll("FixedAmountVoucher creation",
() -> assertThrows(IllegalArgumentException.class, () -> new FixedAmountVoucher(UUID.randomUUID(), 0)),
() -> assertThrows(IllegalArgumentException.class, () -> new FixedAmountVoucher(UUID.randomUUID(), -100)),
() -> assertThrows(IllegalArgumentException.class, () -> new FixedAmountVoucher(UUID.randomUUID(), 1000000))
);
}
}
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.*;
import static org.junit.jupiter.api.Assertions.*;
public class HamcrestAssertionTests {
@Test
@DisplayName("여러 hamcrest matcher 테스트")
void hamcrestTest() {
assertEquals(2, 1 + 1);
assertThat(1 + 1, equalTo(2));
assertThat(1 + 1, is(2));
assertThat(1 + 1, anyOf(is(1), is(2)));
assertNotEquals(1, 1 + 1);
assertThat(1 + 1, not(equalTo(1)));
}
@Test
@DisplayName("컬렉션에 대한 matcher 테스트")
void hamcrestListMatcherTest() {
var prices = List.of(2, 3, 4);
assertThat(prices, hasSize(3));
assertThat(prices, everyItem(greaterThan(1)));
assertThat(prices, containsInAnyOrder(3, 4, 2));
assertThat(prices, hasItem(greaterThanOrEqualTo(2)));
}
}
단위테스트에서의 테스트 더블은 SUT와 의존관계에 있는 객체를 사용할 수 없을 때 SUT와 상호작용을 하기 위해서 만든 객체입니다.
테스트 더블에는 여러 종류가 있으며 대표적인 두 가지가 Mock과 Stub입니다.
목 객체를 가짜 객체로 생각할 수 있으나 실제로 Stub이 가짜 객체이며 목 객체는 호출에 대한 기대를 명세합니다. 그때 어떻게 동작해야하는지 내용에 대해서 기술이된 객체로 행위에 대해서 집중을 하는 객체입니다.
Stub은 실제 동작하는 것처럼 보이게 하는 객체로 예를 들어 A클래스가 B클래스에 의존관계를 가지며 B가 인터페이스라고 할 때 B를 구현한 Stub을 만들어 SUT에 대해서 상태를 확인하며 올바르게 동작하는지 검증합니다.
목 오브젝트는 행위 검증(behavior verification)을 사용하고, stub을 포함한 다른 대역들은 상태 검증(state verification)을 사용합니다.
상태 검증
: 메소드가 수행된 후, 객체의 상태를 확인하여 올바르게 동작했는지를 확인하는 검증법입니다.행위 검증
: 메소드의 리턴 값으로 판단할 수 없는 경우 특정 동작을 수행하는지 확인하는 검증법입니다