[RUST] 러스트 프로그래밍 공식 가이드(제2판) 11장 요약
자동화 테스트 작성하기
테스트 작성 방법
- 테스트란, 테스트 할 코드가 의도대로 기능하는지 검증하는 함수를 말하며, 보통 아래 3가지 동작을 수행함
- 필요한 데이터나 상태 설정
- 테스트할 코드 실행
- 의도한 결과가 나오는지 확인
테스트 함수 파헤치기
- 러스트에서 테스트란
test속성(러스트 코드 조각에 대한 메타데이터를 의미)이 애너테이션된 함수를 말하며fn이전 줄에#[test]를 추가하면 테스트 함수로 변경 됨 - 테스트는
cargo test명령어로 실행되며, 이 명령어를 실행하면 러스트는 속성이 표시된 함수를 실행하고 결과를 보고하는 테스트 실행 바이너리를 빌드함 - 카고로 새 라이브러리 프로젝트를 생성할 때 마다 테스트 함수가 포함된 테스트 모듈이 자동으로 생성됨 (테스트 작성을 위한 템플릿을 제공)
ssert! 매크로로 결과 검사하기
- 어떤 조건이
true임을 보장하는 테스트를 작성할 땐 표준라이브러리가 제공하는assert!매크로가 유용 assert!매크로는 불리언값으로 평가되는 인수를 전달받고, true 값일 경우 아무일도 일어나지 않고 테스트는 통과하고 false 값일 경우panic!매크로를 호출하여 테스트를 실패하도록 만듦
assert_eq!, assert_ne! 매크로를 이용한 동등 테스트
- 두 매크로는 각각 동등한지(equanlity) 그렇지 않은지(inequality) 판단하고, 단언 코드가 실패하면 두 값을 출력하여 테스트 실패 사유를 더 알기 쉽게 보여줌
- 러스트의 단언 함수의 매개변수는
left,right라고 지칭하며 예상값과 테스트 코드로 만들어진 값의 순서는 상관이 없음 assert_eq!매크로는 내부적으로==연산자를 사용 (같으면 통과)assert_ne!매크로는 내부적으로!=연산자를 사용 (같지 않으면 통과)하며 적어도 이 값은 되지 않아야 함을 알고 있는 경우에 유용- 두 매크로는 비교 연산자를 사용하므로 비교 대상 타입은 반드시
PartialEq트레이트를 구현해야 하며, 던언에 실패시{:?}디버그 포맷으로 두 값 (left,right)을 출력하므로Debug트레이트도 구현해야 함
커스텀 실패 메시지 추가하기
assert!,assert_eq!,assert_ne!매크로에 필수적인 인수들 이후의 인수는format!매크로로 전달 되기 때문에{}자리표시자가 들어있는 포맷 문자열과 자리표시자에 들어갈 값을 전달할 수 있음- 커스텀 메시지는 테스트 단언의 의미를 서술하는데 유용
should_panic 매크로로 패닉 발생 검사하기
#[should_panic]속성은 테스트 내부에서 패닉이 발생해야 통과되고, 패닉이 발생하지 않으면 실패should_panic을 사용하는 테스트는 의도한 것과 다른 이유로 패닉이 발생하더라도 테스트가 통과하기 때문에 정확하지 않은데, 이때should_panic의 속성에expected매개변수를 추가해 포함되어야 하는 메시지를 지정할 수 있음- 매개변수 값이 패닉 메시지 문자열의 일부라면 테스트는 통과
- 매개변수 값이 패닉 메시지 문자열에 포함되지 않는다면 테스트는 실패
Result<T,E>를 이용한 테스트
- 테스트는
Result<T,E>타입을 반환할 수 있으며, 테스트 성공시에는Ok()를 실패 시에는Err()를 반환할 수 있고#[should_panic]애너테이션을 사용할 수 없음 Err배리언트를 반환하는 것을 단언하려면Result<T, E>에 ? 연산자를 사용하지 않고assert!(value.is_error())를 사용
테스트 실행 방법 제어하기
cargo test는 커맨드 라인 옵션을 지정하여 기본 동작을 변경할 수 있음- 명령어 옵션은
cargo test에 전달되는 것도 있고, 테스트 바이너리에 전달되는 것도 있으며 이 둘을 구분하기 위해cargo test에 전달할 인수를 먼저 나열하고, – 구분자를 쓰고, 그 뒤에 테스트 바이너리에게 전달할 인수를 나열
테스트를 병렬 혹은 순차적으로 실행하기
- 여러 테스트를 실행할 때는 기본적으로 스레드를 사용해 병렬로 실행됨 (여러 테스트가 동시에 실행되므로, 각 테스트가 공유상태(공유자원, 현재 작업 디렉터리, 환경 변수 등)를 갖거나 다른 테스트에 의존해서는 안됨)
- 테스트를 병렬로 실행하고 싶지 않거나, 사용할 스레드의 개수에 대해 미세 조정이 필요한 경우
--test-threads플래그와 함께 테스트 바이너리에서 사용할 스레드 개수를 지정 (cargo test -- --test-threads=1)
함수 출력 표시하기
- 기본적으로 러스트 테스트 라이브러리는 성공한 테스트의 모든 표준 출력을 캡처함 (캡처: 즉시 터미널에 보여주는 게 아니라 일단 내부적으로 가로채서 저장)
- 테스트에서
println!매크로를 호출해도, 해당 테스트가 성공하면 터미널에서println!출력을 찾아볼 수 없음 (테스트 실패 시 표준 출력으로 출력됐던 모든 내용이 실패 메시지 아래 표시) - 성공한 테스트에서 출력한 내용도 보고 싶다면, 러스트에게
—show-output옵션을 전달하여 성공한 테스트 출력도 표시할 수 있음 (cargo test — —show-output)
이름을 지정해 일부 테스트만 실행하기
테스트 하나만 실행하기
cargo test명령어에 테스트 함수의 이름을 인수로 넘겨 어떤 테스트를 실행할지 선택 (cargo test one_hundred)- 이름이 맞지 않는 테스트는 필터링되며 테스트 결과 마지막 요약 라인에
2 filtered out와 같이 표시하고, 실행한 테스트 이외에도 다른 테스트가 존재함을 알려줌
테스트를 필터링하여 어러 테스트 실행하기
- 테스트 이름의 일부만 지정하면 해당 값에 맞는 모든 테스트가 실행 (
cargo test add를 실행하면 함수명에 add 가 포함된 테스트가 실행됨) - 테스트가 위치한 모듈도 테스트 이름의 일부로 나타나며, 모듈 이름으로 필터링하면 해당 모듈 내 모든 테스트를 실행함
특별 요청이 없다면 일부 테스트 무시하기
- 제외하고싶은 테스트가 있다면 ignore 속성(
#[ignore])을 애너테이션 하여 테스트에서 제외 시킬 수 있음 cargo test -- --ignored명령어를 사용하면 무시된 테스트만 실행할 수 있음- 무시되었건 말건 모든 테스트를 실행하고 싶다면
cargo test -- --include-ignored를 실행 할 수 있음
테스트 조직화
- 유닛 테스트 : 한 번에 하나의 모듈만 테스트하며, 모듈의 비공개 인터페이스도 테스트할 수 있음
- 통합 테스트 : 완전히 라이브러리 외부에 위치하며, 직접 작성한 라이브러리를 외부 코드에서 사용할 때와 똑같은 방식으로 사용하여 여러 모듀을 실제 사용 방식에 가깝게 결합해 전체 동작이 의도대로 동작하는지 검증하는 테스트
유닛 테스트
- 유닛 테스트의 목적 : 각 코드 단위를 나머지 코드와 분리하여, 제대로 작동하지 않는 코드가 어느 부분인지 빠르게 파악하는 것
- src 디렉터리 내의 각 파일에 테스트 대상이 될 코드와 함께 작성하며, 각 파일에 tests 모듈을 만들고
cfg(test)를 애너테이션하는 게 일반적인 관례
테스트 모듈과 #[cfg(test)]
- 테스트 모듈에 애너테이션하는
#[cfg(test)]은 이 코드가cargo test명령어 실행 시에만 컴파일 및 실행 될 것이라는 점을 러스트에 전달 (cfg속성을 사용하면 카고는cargo test명령어를 실행할 때만 테스트 코드를 컴파일 함) - 유닛 테스트는 일반 코드와 같은 파일에 위치하기 때문에
#[cfg(test)]애너테이션을 작성해 컴파일 결과물에 포함되지 않도록 명시해야 함
비공개 함수 테스트하기
- 러스트의 비공개 규칙은 비공개 함수를 테스트하도록 허용 함
통합 테스트
- 통합 테스트의 목적 : 라이브러리의 여러 부분을 함께 사용했을 때 제대로 작동하는지 확인하는 것
tests 디렉터리
- 프로젝트 디렉터리의 아래 tests 디렉터리를 생성하면 카고는 디렉터리 내 통합 테스트 파일을 자동으로 인식 함
- 원하는 만큼 통합 테스트 파일을 만들 수 있고, 카고는 각 파일을 개별 크레이트로 컴파일 함
- cargo test 명령어에 테스트 함수명을 인수로 전달해 특정 통합 테스트 함수를 실행할 수 있음
- 특정 통합 테스트 파일의 모든 테스트를 실행하려면
cargo test명령어에--test인수로 파일명을 전달
통합 테스트 내 서브 모듈
tests디렉터리 안의 파일들은 각각 독립된 크레이트로 컴파일하는데, tests/common.rs 와 같이 사용하는 대신 tests/common/mod.rs 처럼 사용하면 통합 테스트 크레이트로 취급되지 않고 일반 모듈로 동작함
바이너르 크레이트에서의 통합 테스트
- 바이너리 크레이트는 tests 디렉터리에 통합 테스트를 만들어서 src/main.rs 파일에 정의된 함수를
use구문으로 가져올 수 없음 (다른 크레이트에서 가져다 쓸 수 있게 노출하는 건 라이브러리 크레이트 뿐) - 주요 기능을
lib.rs로 옮겨 통합 테스트에서 use 구문으로 가져와 테스트하고main.rs는 실행용으로만 사용
This post is licensed under CC BY 4.0 by the author.