[C#/NUnit] NUnit 테스트 전후 처리, SetUpAttribute & TearDownAttribute

반복되는 마무리 처리

오늘, 단위 테스트를 진행하다가 난감한 상황을 맞닥뜨렸습니다.
단위 테스트 대상 메서드는 ADB를 통해 특정 작업을 시행한 뒤 Redirect된 출력을 바탕으로 내용을 분석해 원하는 결과가 나왔는지 체크하는 메서드였는데요.
문제는, ADB 프로세스를 처음 실행할 때, 데몬 모드로 프로세스가 꺼지지 않게 계속 실행된다는 것입니다.
이 문제를 해결하기 위해서, 여러 시도를 했습니다. 우선, 매 adb 명령이 완료될 때마다 프로세스 리스트에서 adb를 모두 종료하는 방식이 첫번째였죠. 하지만, 이 경우에 ADB 작업이 실행될 때마다 데몬이 켜지길 반복하기 때문에, 심각할 정도의 CPU 자원 낭비, 즉 딜레이가 생겼습니다.
그래서, ADB 관련 처리를 하는 클래스에 IDisposable을 구현한 뒤, Dispose() 메서드에서 전체 adb 프로세스를 죽이는 작업을 처리하도록 했습니다. 이러면 아래와 같이 사용할 수 있죠.
using (var manager = new AdbManager())
{
    // TODO: Process...
}
실사용에선 별 문제가 없어 보입니다. 그렇지만, 고작 단위 테스트 하나를 위해서 저렇게 해야될까요? 당연히 아닙니다. 제가 사용하는 NUnit 테스트 프레임워크엔 이럴 경우를 위한 어트리뷰트가 마련돼 있습니다. 물론, 다른 프레임워크도 비슷한 기능이 있으나, 이번에 제가 포스팅할 것은 제가 사용하는 NUnit에 대해서입니다.

SetUpAttribute, TearDownAttribute

바로 SetUpAttributeTearDownAttribute입니다. 각각 단위 테스트를 시작하기 전, 그리고 단위 테스트를 마친 후 시행될 작업을 정의할 메서드에 붙여주시면 됩니다.
지금 제 상황에 맞게 코딩해볼까요?
[TestFixture]
public class AdbManagerTests
{
    // 다른 수많은 비슷한 테스트 메서드들...

    [Test]
    public void GetCurrentNetworkStatusTest()
    {
        // adb shell dumpsys telephony.registry 출력에 따라 현재 모바일 연결 상태를 가져옴
        // adb shell su -c dumpsys wifi 출력에 따라 현재 와이파이 연결 상태를 가져옴

        // 작업 진행 중 Assert 예외 발생
        Assert.IsTrue(false);

        // 다른 수많은 테스트...

        // 테스트 종료
    }

    // 다른 수많은 비슷한 테스트 메서드들...

    // 모든 테스트가 완료된 뒤 남아있는 adb 프로세스 정리
    [TearDown] // 이 메서드를 모든 테스트가 완료된 뒤 시행하겠다는 의미의 Attribute
    public void Cleanup()
    {
        Process.GetProcessesByName("adb").ToList().ForEach(p => p.Kill());
    }
}
이 경우, AdbManagerTests 테스트 픽스쳐에 대해 단위 태스트를 진행하면, 아래와 같이 처리가 됩니다.
  1. 수많은 문제 없는 단위 테스트가 성공
  2. GetCurrentNetworkoStatusTest 단위 테스트 실행
    1. Assert.IsTrue(false); 실행
    2. Assert.IsTrue(false); 에서 예외 발생
  3. 다른 수많은 문제없는 단위 테스트가 성공
  4. Cleanup 메서드 실행
    1. 모든 adb 프로세스가 종료됨.
즉, 모든 테스트가 완료된 뒤, 예외 발생에 상관없이 Cleanup 메서드가 실행됩니다.
SetUpAttribute도 같은 방식으로 생각하시면 됩니다. 모든 테스트가 시작되기 실행되는 메서드를 지정하는 것이죠.
[TestFixture]
public class AdbManagerTests
{
    // 모든 테스트 메서드가 실행되기 전, ADB를 인터넷으로부터 다운로드
    [SetUp]// 이 메서드를 모든 테스트 메서드가 실행되기 전에 실행시키겠다는 어트리뷰트
    public void Init()
    {
        DownloadAdbFromInternet();
    }
    // 다른 수많은 비슷한 테스트 메서드들...

    [Test]
    public void GetCurrentNetworkStatusTest()
    {
        // adb shell dumpsys telephony.registry 출력에 따라 현재 모바일 연결 상태를 가져옴
        // adb shell su -c dumpsys wifi 출력에 따라 현재 와이파이 연결 상태를 가져옴

        // 작업 진행 중 Assert 예외 발생
        Assert.IsTrue(false);

        // 다른 수많은 테스트...

        // 테스트 종료
    }

    // 다른 수많은 비슷한 테스트 메서드들...
아, 혹시 몰라 말씀드리지만, SetUpAttributeTearDownAttribute가 붙어있다면 테스트 픽스쳐 내 메서드 순서와 상관없이 맨 처음, 혹은 맨 마지막에 실행됩니다. 그러나, 나중에 알아보기 편하려면 SetUpAttribute가 붙은 메서드는 맨 위에, TearDownAttribute가 붙은 메서드는 맨 아래, 혹은 SetUpAttribute가 붙은 메서드 바로 밑에 붙이는 등 본인의 규칙대로 정렬하는 게 좋겠죠?
더 자세한 설명은 영어가 되신다면 이 링크에서 보실 수 있습니다.

댓글

이 블로그의 인기 게시물

C# 남아도는 메모리에도 불구하고 OutOfMemoryException이 발생한다면?

USB를 뒤는 괜찮은데 앞에 꽂으면 인식이 힘들다?

MySQL 데이터 타입과 Java 데이터 타입 비교/매칭