학습 테스트환경 구축

AKKA 코드를 테스트를 하기위해서 다음과 같은 방법이 있습니다.

  • 간단하게 사용자 정의 클래스 생성하여 학습 코드 집합
  • VisualStudio에 유닛테스트 프로젝트활용
  • 분산환경 메시지 Test를 위해 AKKA Test Toolkit사용


 Actor 개념을 익히기까지는,유닛테스트를 사용하지 않고

사용자 정의 테스트 클래스를 통해 실습을 진행하겠습니다.

유닛테스트는 충분한 이해를 바탕으로 다양한 시나리오를 검증하는것이기때문에 

Actor 이후부터는 VisualStudio의 순수 유닛테스트기를 통해서만 샘플 진행예정입니다.


AKKA가 분산환경에서의 메시지 처리기술을 다루고 있기때문에, 실제 서비스 코드작성하게될시

메시지처리에대한 단위테스트가 요구되며, AKKATestToolKit은 메시지처리에대한 유닛 테스트를 지원합니다.

로컬액터에 대한 이해후 RemoteTest시 활용할것을 권장드립니다.


취향에맞게 자신만의 학습코드 테스트 환경을 구축하면되겠습니다.


사용자 정의 테스트 클래스 작성



Actor를 학습하고 테스트하는 Class
using Akka.Actor;

namespace ServiceA.STUDY
{
    public class ActorTest  //Actor 기본 테스트를 위해서~~
    {
        protected ActorSystem actorSystem;

        public ActorTest(ActorSystem system)  //메인 APP에서 생성한 AKKA System만 참조하면 됩니다.
        {
            actorSystem = system;
        }

        protected void SomeTest1()
        {

        }

        public void RunAll()
        {
            SomeTest1(); //SubTest

        }
    }
}


 이렇게 하는 이유는 단지, 기존 어플리케이션 코드에서 학습 진행한 코드를 섹션별로 분리목적으로 큰 의도는 없습니다.

위와 같은 템플릿은 ActorTest외에 , RemoteActorTest , ClusterActorTest 등 학습 목적에따라 Class로 분리예정이며

생성패턴이 유사하니 추가로 언급하지 않겠습니다.


APP Main 진입점
using Akka.Actor;

using ServiceA.STUDY;

namespace ServiceA
{
    class Program
    {
        static void Main(string[] args)
        {
            ConsoleKeyInfo cki;
            Console.CancelKeyPress += new ConsoleCancelEventHandler(myHandler);
            using (ActorSystem system = ActorSystem.Create("ServiceA"))
            {
                //Actor의 시스템 준비 완료

                //ActorTest -ActorTest코드는 아래 두줄외에 더이상 추가가 안됩니다.
                ActorTest actorTest = new ActorTest(system);
                actorTest.RunAll();

                while (true)
                {
                    // 메인 어플리케이션 종료방지를 위한코드 ( ctrl+x 종료 )
                    cki = Console.ReadKey(true);
                    if (cki.Key == ConsoleKey.X) break;
                }
            }
        }

        protected static void myHandler(object sender, ConsoleCancelEventArgs args)
        {
            args.Cancel = true;
        }
    }
}


Visual Studio에서 제공하는 UnitTest 사용하기


 간단한 단위 테스트를 이용할때는, 직접 테스트 클랙스를 작성하여 콘솔환경에서 수행하는것보다

IDE에서 제공하는 유닛 테스트프로젝트를 이용하는것이 더 편리하고 강력합니다.

AKKA의 기본기능을 배우기위해서는, 유닛테스트 템플릿 프로젝트로 충분합니다.


테스트 코드를 서비스 코드와 완전하게 분리할수 있습니다.

 서비스코드는 서비스에 필요한 각종 액터,메시지정의가 포함될수 있습니다.

Test프로젝트는 서비스프로젝트를 참조하여, 서비스내에서 정의한 객체들을 참조를통해

테스트 수행 가능합니다.


테스트를 단위혹은 그룹별실행 가능하며, 출력및 유효검사가 편리합니다.



AKKA 유닛테스트 샘플

using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Event;

using ServiceA.STUDY;


namespace AkkaTest
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            using (ActorSystem actorSystem = ActorSystem.Create("ServiceA"))  //실제 서비스에서사용될 유사한 코드를 가지고 테스트
            {
                IActorRef myActor = actorSystem.ActorOf<BasicActor>("myactor");
                Props watchProps = WatchActor.Props(myActor);
                IActorRef watcher = actorSystem.ActorOf(watchProps, "watcher");
                var result = myActor.Ask("나는 살아있다.").Result;
                actorSystem.Stop(myActor); //myActor를 임의로 Stop하여, watcher가 종료를감시한는지 체크
                myActor.GracefulStop(TimeSpan.FromSeconds(10)).Wait();  //생성한 Actor를 안전하게 종료시킨다.
            }            
        }
    }
}

출력:

테스트 이름:	TestMethod1
테스트 결과:	성공
Result StandardOutput:	
[DEBUG][2017-09-12 오전 1:29:23][Thread 0022][EventStream(ServiceA)] Logger log1-DefaultLogger [DefaultLogger] started
[DEBUG][2017-09-12 오전 1:29:23][Thread 0022][EventStream(ServiceA)] StandardOutLogger being removed
[DEBUG][2017-09-12 오전 1:29:23][Thread 0022][EventStream(ServiceA)] Default Loggers started
[INFO][2017-09-12 오전 1:29:23][Thread 0022][remoting] Starting remoting
[DEBUG][2017-09-12 오전 1:29:23][Thread 0029][remoting] Starting prune timer for endpoint manager...
[INFO][2017-09-12 오전 1:29:23][Thread 0022][remoting] Remoting started; listening on addresses : [akka.tcp://ServiceA@127.0.0.1:8001]
[INFO][2017-09-12 오전 1:29:23][Thread 0022][remoting] Remoting now listens on addresses: [akka.tcp://ServiceA@127.0.0.1:8001]
[INFO][2017-09-12 오전 1:29:23][Thread 0004][[akka://ServiceA/user/myactor#1560625506]] BasicActor:GetSomeMessage 나는 살아있다.
[INFO][2017-09-12 오전 1:29:23][Thread 0008][[akka://ServiceA/user/watcher#2126936690]] WatchActor:GetSomeMessage <Terminated>: [akka://ServiceA/user/myactor#1560625506] - ExistenceConfirmed=True
[INFO][2017-09-12 오전 1:29:23][Thread 0008][[akka://ServiceA/user/watcher#2126936690]] 감시대상이 사라짐
[DEBUG][2017-09-12 오전 1:29:23][Thread 0022][ActorSystem(ServiceA)] Disposing system
[DEBUG][2017-09-12 오전 1:29:23][Thread 0022][ActorSystem(ServiceA)] System shutdown initiated




AKKA Test Toolkit 사용하기


  각종 리모트,클러스터환경에서의 메시지 검증을 위해서 AKKA TestTookit을 제공합니다. ( JAVA에서 제공하는 AKKA TestToolkit과 컨셉이 동일합니다.)

기존 VS 유닛 테스트기와 연동되어 사용이 가능해집니다.

유닛테스트에서 지원되는 일반적인 기능은 순차적인 흐름을 통해 테스트가 진행이되며,

Actor의 동시성 처리처리를 확인하려면 Result를 기다리는 Block 코드가필요하며 

테스트 단계에 넣지않으면 Assert로 유효검증이 어렵습니다.

ExpectMsg("Re:Hello", TimeSpan.FromSeconds(1));  그래서 AkkaToolkit에서는 , 1초이내에 예상메시지 라는 추가 검증 방법을

지원하면서 흐름을 끊지 않고 메시지에대한 검증이 가능합니다. 즉 우리가 테스트 하려는 코드 자체에 대해서는 블락킹처리없이

별도의 테스트 지원 함수로 비동기메시지에대한 검증 과정을 할수가 있습니다.


로컬액터를 이해하고, Remote 이후에 이방식에대해 자세한 설명후

Akka Test Toolkit을 활용하여 이론에대한 부분 검증을 하도록 하겠습니다.  현재는 이러한게 있고만  설정하는 방법만 알고 계시면 됩니다.


-실제 메시지 처리에 대한 유효검사가 용이해집니다.

-여러가지 가상의 환경을 셋팅하여 AKKA의

기능에관련된 메시징 기능 체크가 가능합니다.

-이것이 가능한 이유는 기본 유닛테스트 클래스가

액터기반으로 작동이 되기때문입니다.


설치(기존 유닛 테스트에 추가 설치)


사용예

using ServiceA.STUDY;

using Akka.TestKit.VsTest;

namespace AkkaTest
{
    [TestClass]
    public class UnitTest1 : TestKit //TestKit을 상속받습니다.
    {
        [TestMethod]
        public void TestMethod1()  //기본 유닛 테스트기
        {
            using (ActorSystem actorSystem = ActorSystem.Create("ServiceA"))
            {
                IActorRef myActor = actorSystem.ActorOf<BasicActor>("myactor");
                Props watchProps = WatchActor.Props(myActor);
                IActorRef watcher = actorSystem.ActorOf(watchProps, "watcher");
                var result = myActor.Ask("나는 살아있다.").Result;
                actorSystem.Stop(myActor); //myActor를 임의로 Stop하여, watcher가 종료를감시한는지 체크
                myActor.GracefulStop(TimeSpan.FromSeconds(10)).Wait();  //생성한 Actor를 안전하게 종료시킨다.
            }            
        }

        [TestMethod]
        public void TestMethod2()  //Akka Tookit을 이용한 유닛테스트, 테스트기에 테스트를 할수 있는 액터가 추가됨
        {
            //실제 서비스코드와는 다른 패턴이기때문에, 학습용으로는 적당하지 않습니다.
            var myActor = this.Sys.ActorOf<MyActor>("myActor");  //MyActor는 사용자의 메시지에 Re:+ 를 붙여 응답합니다.
            var probe = this.CreateTestProbe();
            myActor.Tell("Hello", this.TestActor);
            ExpectMsg("Re:Hello", TimeSpan.FromSeconds(1));            
        }

    }
}




  • No labels