文章目录
《Akka学习笔记:ACTORS介绍》
《Akka学习笔记:Actor消息传递(1)》
《Akka学习笔记:Actor消息传递(2)》
《Akka学习笔记:日志》
《Akka学习笔记:测试Actors》
《Akka学习笔记:Actor消息处理-请求和响应(1) 》
《Akka学习笔记:Actor消息处理-请求和响应(2) 》
《Akka学习笔记:ActorSystem(配置)》
《Akka学习笔记:ActorSystem(调度)》
在《Akka学习笔记:日志》文章中介绍了Akka的日志功能。本文主要介绍如何测试Actors。
测试Akka
StudentSimulatorApp程序做了该做的事情,你肯定同意将它写成一个测试用例。为了减少测试的烦恼, Akka提供了一些很强大的工具包,利用它我们可以做一些很神奇的事情,比如直接探讨Actor内部的实现。
好了,说的够多了!让我们来看下这个测试用例。我们现将StudentSimulatorApp程序改成一个Testcase。如下图:
让我们先看下测试用例的声明:
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)
额 很好
很好!