Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Info

언어와 상관없이 모던한 개발 프레임워크 템플릿들은 유닛테스트를 기본적으로 포함하고 있습니다.

자신이 작성한 서비스 코드에 대한 유닛테스트 작성이 처음이라고 하면 , Nunit/xUnit 적합한 유닛테스트를 먼저 선택을 해야하며 

여기서는 실시간 메시지에대한 유닛테스트기를 어떻게 검증을 할것인가? 실시간 메시지를 조금더 우아하게 테스트할수 있는 방법을 살펴보겠습니다 


준비하기


디렉토리 구조

유닛테스트를 위한 올바른 디렉토리 구조

Warning

만약 자신의 프로젝트 소가 루트에서부터 시작한다고 하면, 수정을 권장드립니다.

그러한 디렉토리구조는 이 프로젝트는 앞으로 유닛테스트가 필요없음을 명시하는 방법입니다.



종속성

Code Block
languagec#
themeEmacs
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.2</TargetFramework>

    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Akka.TestKit" Version="1.3.5" />
    <PackageReference Include="Akka.TestKit.NUnit3" Version="1.3.2" />
    <PackageReference Include="nunit" Version="3.11.0" />
    <PackageReference Include="NUnit3TestAdapter" Version="3.11.0" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
    <PackageReference Include="Akka" Version="1.3.5" />
  </ItemGroup>

</Project>


여기서 샘플은 Nunit를 선택하였습니다. 


유닛 테스트 작성하기

서비스 코드

Code Block
languagec#
themeEmacs
linenumberstrue
using System;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Event;

namespace AkkaNetCore.Actors
{
    public class CashGateActor : ReceiveActor
    {
        private readonly ILoggingAdapter logger = Context.GetLogger();
        private readonly string id;
        private Random rnd;

        public CashGateActor(int delay)
        {
            rnd = new Random();
            id = Guid.NewGuid().ToString();
            logger.Info($"현금정산게이트 액터 생성:{id} {delay}");

            ReceiveAsync<string>(async msg =>
            {
                //현금정산에 걸리는시간 1~10초, 0일때는 랜덤, 값이 주어질땐 주어진만큼                 
                int auto_delay = delay==0 ? rnd.Next(1000, 10000) : delay;
                await Task.Delay(auto_delay);
                logger.Info($"{msg}-{auto_delay}");
                Sender.Tell($"정산완료 통과하세요");
            });
        }        
    }
}

앞장 성능 확장을 위한 톨게이트 모델에서 현금정산소 Actor를 이용하여 메시지에대한 유닛테스트를 작성해보겠습니다.

메시지를 받으면 지정된 지연시간만큼(for test) 응답을 하는 심플한 코드입니다. -모듈작성때부터 유닛테스트 가능한 방법으로 작성이되면, 유닛테스트 이용과는 별개로 테스트가능한 모듈은 사용성도 높아지게되며 결국 코드품질이 높아지게됩니다.


유닛테스트

테스트 작성

Code Block
languagec#
themeEmacs
linenumberstrue
using System;
using Akka.Actor;
using Akka.TestKit;
using Akka.TestKit.NUnit3;
using AkkaNetCore.Actors;
using NUnit.Framework;

namespace AkkaNetCoreTest.Actors
{
    class ActorBaseTest : TestKit
    {
        TestProbe probe;

        [SetUp]
        public void Setup()
        {
            probe = this.CreateTestProbe();
        }
        
        [TestCase(100, 300)]
        public void Actor_should_respond_within_max_allowable_time(int delay, int cutoff)
        {
            var cashGate = Sys.ActorOf(Props.Create(() => new CashGateActor(delay)));
            // sets a maximum allowable time for entire block to finish
            Within(TimeSpan.FromMilliseconds(cutoff), () =>
            {
                cashGate.Tell("정산게이트 통과요청");
                ExpectMsg("정산완료 통과하세요");
            });
        }
    }
}

테스트 수행

이렇게 작성되어진 유닛테스트는 테스트 탐색기를 통해 특정 테스트만 수행할수도 있고 전체를 수행할수도 있습니다.

비동기 처리메시지를 액터와 연동함으로 비동기 메시징에 대한 처리를 유연하게 함과 동시에 심플하고 강력한 방법으로 유닛테스트기를 작성할수가 있습니다.


Note

간혹 카프카를 사용하여 시스템간 메시징 처리시스템이 구현되어야 할경우 Actor사용이 필요 없을수도 있습니다.
하지만 이것은 잘못된 생각입니다.
Kafka와 연동된 커스텀 모듈이 동기처리를 한다거나, 로컬내에서 올바른 분배전략을 세우지 못한다고
유닛테스트가 불가능하다고 하면 Kafka의 끝점연결을 Actor로 하는것을 고려해보십시오
사용해야할 메시징이 늘어남에따라 KafkaTools에서 메시지 검사를 수동으로 하는것이 언젠가 한계가 올것입니다.


참고링크