欢迎关注大数据技术架构与案例微信公众号:过往记忆大数据
过往记忆博客公众号iteblog_hadoop
欢迎关注微信公众号:
过往记忆大数据

Akka学习笔记:测试Actors

  在《Akka学习笔记:日志》文章中介绍了Akka的日志功能。本文主要介绍如何测试Actors。

测试Akka

  StudentSimulatorApp程序做了该做的事情,你肯定同意将它写成一个测试用例。为了减少测试的烦恼, Akka提供了一些很强大的工具包,利用它我们可以做一些很神奇的事情,比如直接探讨Actor内部的实现。
  好了,说的够多了!让我们来看下这个测试用例。我们现将StudentSimulatorApp程序改成一个Testcase。如下图:


如果想及时了解Spark、Hadoop或者Hbase相关的文章,欢迎关注微信公共帐号:iteblog_hadoop

  让我们先看下测试用例的声明:

class TeacherPreTest extends TestKit(ActorSystem("UniversityMessageSystem"))  
  with WordSpecLike
  with MustMatchers
  with BeforeAndAfterAll {

  从TestCase类的声明中我们可以看出:
  1、TestKit是一个trait,它接收一个ActorSystem对象,通过ActorSystem我们可以创建Actors。从内部实现来说,TestKit 装饰了ActorSystem,并且替换了默认的dispatcher;
  2、我们这里用到了WordSpec,在是编写有趣ScalaTest的一种方式;
  3、MustMatchers提供了一种非常方便的方法,使得将testcase 看起来和正常的语言一样;
  4、我们嵌入了BeforeAndAfterAll 来在testcases运行完的时候关闭ActorSystem。afterAll 方法看起来和JUnit中的tearDown方法类似。

1, 2 - 给Actor发送消息

  1、第一个测试用例仅仅将消息发送给PrintActor,不做任何的检查;
  2、第二个测试用例将消息发送到 Log actor,而 Log actor用ActorLogging 的相应方法将消息发送到EventStream,它同样不做任何的检查。测试用例代码如下:

//1. Sends message to the Print Actor. Not even a testcase actually
  "A teacher" must {

    "print a quote when a QuoteRequest message is sent" in {

      val teacherRef = TestActorRef[TeacherActor]
      teacherRef ! QuoteRequest
    }
  }

  //2. Sends message to the Log Actor. Again, not a testcase per se
  "A teacher with ActorLogging" must {

    "log a quote when a QuoteRequest message is sent" in {

      val teacherRef = TestActorRef[TeacherLogActor]
      teacherRef ! QuoteRequest
    }

3、检查Actors的内部状态

  第三个测试用例用TestActorRef 中的underlyingActor 方法,然后在TeacherActor中的quoteList上进行调用,而quoteList 方法仅仅返回quotes list。我们用这个list检查其size。如果调用quoteList 出现了异常,那么请你去检查一下TeacherLogActor类是否写错。代码如下:

//From TeacherLogActor
//We'll cover the purpose of this method in the Testing section
  def quoteList=quotes
   

 //3. Asserts the internal State of the Log Actor. 
"have a quote list of size 4" in {

      val teacherRef = TestActorRef[TeacherLogActor]
      teacherRef.underlyingActor.quoteList must have size (4)
      teacherRef.underlyingActor.quoteList must have size (4)
}

4、检查日志消息

  正如我们在EventStream和日志那段《Akka学习笔记:日志》进行讨论的。所有的日志消息将发送到EventStream 中,而SLF4JLogger将订阅它,然后将那些消息输入到日志文件/控制台中。如果我们直接在测试用例中直接订阅EventStream 那岂不是很棒?然后在那检查日志消息,看起来我们是可以实现的。这包含两步:
  1)、你需要在TestKit上添加额外的配置,如下

class TeacherTest extends TestKit(ActorSystem("UniversityMessageSystem",
    ConfigFactory.parseString("""akka.loggers = ["akka.testkit.TestEventListener"]""")))  
  with WordSpecLike
  with MustMatchers
  with BeforeAndAfterAll { 

  2)、现在我们已经订阅到EventStream上,我们可以从testcase 直接检查:

//4. Verifying log messages from eventStream
    "be verifiable via EventFilter in response to a QuoteRequest that is sent" in {

      val teacherRef = TestActorRef[TeacherLogActor]
      EventFilter.info(pattern = "QuoteResponse*", occurrences = 1) intercept {
        teacherRef ! QuoteRequest
      }
    }

EventFilter.info块仅仅接受以QuoteResponse (pattern='QuoteResponse*)开始的日志。当然,你也可以用start='QuoteResponse'来实现。如果没有消息发送到TeacherLogActor,那么这个测试用例将会失败

5、测试带有构造参数的Actors

  需要注意的是,我们在测试用例中创建Actors的方法是通过TestActorRef[TeacherLogActor],而不是通过system.actorOf。这仅仅是为了能够在TeacherActorRef中通过underlyingActor 方法进入到Actor的内部。我们不能通过ActorRef 实现。
  如果Actor介绍参数,那么我们创建TestActorRef可以如下:

val teacherRef = TestActorRef(new TeacherLogParameterActor(quotes))

整个测试用例看起来如下

//5. have a quote list of the same size as the input parameter
    " have a quote list of the same size as the input parameter" in {

      val quotes = List(
        "Moderation is for cowards",
        "Anything worth doing is worth overdoing",
        "The trouble is you think you have time",
        "You never gonna know if you never even try")

      val teacherRef = TestActorRef(new TeacherLogParameterActor(quotes))
      //val teacherRef = TestActorRef(Props(new TeacherLogParameterActor(quotes)))

      teacherRef.underlyingActor.quoteList must have size (4)
      EventFilter.info(pattern = "QuoteResponse*", occurrences = 1) intercept {
        teacherRef ! QuoteRequest
      }
    }

关闭ActorSystem

最后,通过afterAll关闭ActorSystem:

override def afterAll() {  
    super.afterAll()
    system.shutdown()
  }
本博客文章除特别声明,全部都是原创!
原创文章版权归过往记忆大数据(过往记忆)所有,未经许可不得转载。
本文链接: 【Akka学习笔记:测试Actors】(https://www.iteblog.com/archives/1159.html)
喜欢 (7)
分享 (0)
发表我的评论
取消评论

表情
本博客评论系统带有自动识别垃圾评论功能,请写一些有意义的评论,谢谢!
(2)个小伙伴在吐槽
  1. 额 很好

    harli_xxy2014-10-16 09:20 回复
  2. 很好!

    seeme2014-10-16 08:58 回复