如何使用后备测试问题模式

时间:2016-12-13 06:36:23

标签: scala akka

我有一个演员,要求其他演员和未来可以回退到其他人:

class Subject(db: ActorRef) extends Actor with ActorLogging {

  implicit val timeout = Timeout(1 seconds)
  implicit val ec = context.system.dispatcher

  override def preStart(): Unit = {
    db ? "auth" fallbackTo Future {
      "auth:timeout_error"
    } pipeTo self
  }

  def receive: Receive = {
    case msg: String => log.info(msg)
  }

}

我需要测试回退行为,但不知道该怎么做:

class ActorSpec extends TestKit(ActorSystem("MySpec"))
  with ImplicitSender with WordSpecLike with BeforeAndAfterAll with BeforeAndAfterEach with Matchers {

  val db = TestProbe()

  db.ref ! PoisonPill
  //db not exist anymore
  val subject = system.actorOf(Props(new Subject(db.ref)))

  //Something like: subject should receive "auth:timeout_error"

}

如何正确执行此任务?

2 个答案:

答案 0 :(得分:1)

您可以覆盖接收方法并向TestProbe()

发送消息
import java.sql.*;
public class JDBCDemo {
public static void main(String[] args) {
    String url="jdbc:oracle:thin:@//localhost:1521/xe";
    String un="system";
    String pwd="system";
    Connection con=null;
    Statement stmt=null;
    ResultSet res=null;
    try{
        DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
        System.out.println("Driver Loaded successfully");
    }
    catch(Exception e)
    {
        System.out.println("Driver not loaded");
    }
    try{
        DriverManager.getConnection(url,un,pwd);
        System.out.println("Connection established");
    }
    catch(Exception f)
    {
        System.out.println("Connection not established");
    }
    try{
        String s="Select * from student";
        stmt=con.createStatement();
        res=stmt.executeQuery(s);
        System.out.println("Query executed succesfully");
    }
    catch(Exception e)
    {
        System.out.println("Query not executed");
    }  

答案 1 :(得分:1)

执行测试的最简单方法是重构Subject类,为db参数添加抽象级别。 Subject中没有任何东西本质上取决于db是ActorRef的事实; Subject只需要一些内容即可向String发送查询并收到Future[String]响应。因此,您可以通过接受函数使构造函数更通用:

object Subject {
  type Query = String
  type DBResult = Future[String]
  type DB : (Query) => DBResult

  val defaultAuth : DBResult = Future.successful("auth:timeout_error")

  val authQuery : Query = "auth"

  def queryWithDefault(db : DB, default : DBResult = defaultAuth) : DB = 
    (query : Query) => db(query) fallbackTo default     
}//end object Subject

class Subject(db : Subject.DB) extends Actor with ActorLogging {

  override def preStart() : Unit = {
    db(Subject.authQuery) pipeTo self
  }

  override def receive : Receive = {
    case msg : String => log info msg
  }
}//end class Subject

您现在可以测试queryWithDefault功能而无需使用akka:

import org.scalatest.{Matchers, WordSpecLike}
import org.scalatest.concurrent.ScalaFutures

class SubjectSpec 
  extends Matchers 
  with WorkSpecLike 
  with ScalaFutures {

  val alwaysFail : DB = 
    (query : Query) => Future.failed(new Exception("always fails"))

  import Subject.{defaultAuth, queryWithDefault, authQuery}

  "queryWithDefault" should {
    "always return default when db fails" in {
      val db = queryWithDefault(alwaysFail, defaultAuth)

      whenReady(
        for {
          authQueryRes <- db(authQuery)
          fooQueryRes  <- db("foo")
          defaultRes   <- defaultAuth
        }) {
          authQueryRes shouldEqual defaultRes
          fooQueryRes shouldEqual defaultRes 
        }
    }//end "always return..."
  }//end "queryWithDefault" should
}//end class SubjectSpec

然后,您可以在生产中使用重构的和单元测试的Subject.queryWithDefault函数:

val actorDB : DB = (query : Query) => (db.ref ? query).mapTo[String]

val subject = system.actorOf(Props(queryWithDefault(actorDB, defaultAuth)))