Akka学习笔记:测试Actors

10 篇文章 0 订阅

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

测试Akka

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


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

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

1 class TeacherPreTest extends TestKit(ActorSystem("UniversityMessageSystem")) 
2   with WordSpecLike
3   with MustMatchers
4   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,它同样不做任何的检查。测试用例代码如下:

01 //1. Sends message to the Print Actor. Not even a testcase actually
02   "A teacher" must {
03  
04     "print a quote when a QuoteRequest message is sent" in {
05  
06       val teacherRef = TestActorRef[TeacherActor]
07       teacherRef ! QuoteRequest
08     }
09   }
10  
11   //2. Sends message to the Log Actor. Again, not a testcase per se
12   "A teacher with ActorLogging" must {
13  
14     "log a quote when a QuoteRequest message is sent" in {
15  
16       val teacherRef = TestActorRef[TeacherLogActor]
17       teacherRef ! QuoteRequest
18     }

3、检查Actors的内部状态

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

01 //From TeacherLogActor
02 //We'll cover the purpose of this method in the Testing section
03   def quoteList=quotes
04     
05  
06  //3. Asserts the internal State of the Log Actor.
07 "have a quote list of size 4" in {
08  
09       val teacherRef = TestActorRef[TeacherLogActor]
10       teacherRef.underlyingActor.quoteList must have size (4)
11       teacherRef.underlyingActor.quoteList must have size (4)
12 }

4、检查日志消息

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

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

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

1 //4. Verifying log messages from eventStream
2     "be verifiable via EventFilter in response to a QuoteRequest that is sent" in {
3  
4       val teacherRef = TestActorRef[TeacherLogActor]
5       EventFilter.info(pattern = "QuoteResponse*", occurrences = 1) intercept {
6         teacherRef ! QuoteRequest
7       }
8     }

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

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

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

1 val teacherRef = TestActorRef(new TeacherLogParameterActor(quotes))

整个测试用例看起来如下

01 //5. have a quote list of the same size as the input parameter
02     " have a quote list of the same size as the input parameter" in {
03  
04       val quotes = List(
05         "Moderation is for cowards",
06         "Anything worth doing is worth overdoing",
07         "The trouble is you think you have time",
08         "You never gonna know if you never even try")
09  
10       val teacherRef = TestActorRef(new TeacherLogParameterActor(quotes))
11       //val teacherRef = TestActorRef(Props(new TeacherLogParameterActor(quotes)))
12  
13       teacherRef.underlyingActor.quoteList must have size (4)
14       EventFilter.info(pattern = "QuoteResponse*", occurrences = 1) intercept {
15         teacherRef ! QuoteRequest
16       }
17     }

关闭ActorSystem

最后,通过afterAll关闭ActorSystem:

1 override def afterAll() { 
2     super.afterAll()
3     system.shutdown()
4   }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值