2016-05-25 13 views
0

現在、私はMongoデータベースとインターフェースするScalaにREST APIを構築しています。問題のapiアクションは、ユーザーを「ユーザー」コレクションに作成します。ReactMongo Mockitoを使ってMockitoを使って例外を確認しました

ユニークなキー制約に違反するレコードを作成しようとすると、データベース・ドライバがDatabaseExceptionをスローするユニット・テストに関する問題をカバーしようとしています。 Mockitoを使用して、私はこれまでのところ、これを持っている:

describe("a mongo db error") { 

    val collection = mockCollection(Some("users")) 

    doThrow(GenericDatabaseException("Test exception", None)) 
     .when(collection) 
     .insert(any(), any())(any(), any()) 

    val userRequest = CreateUserRequest("test", "test", "test") 
    val request = FakeRequest().withJsonBody(Json.toJson(userRequest)) 
    val result = call(controller.post, request) 
    val response = Json.fromJson[GenericResponse](contentAsJson(result)).get 

    it("should return a bad request") { 
     response.status must be("Failed") 
    } 
    } 

これは、テスト対象のAPIメソッドである:

def post = Action.async(parse.json) { implicit request => 
request.body.validate[CreateUserRequest].map { 
    case model => { 
    collection flatMap { c => 

     val hashedPassword = SecureHash.createHash(model.password) 

     c.insert(User(model.username, hashedPassword, model.emailAddress)) flatMap { r => 
     c.indexesManager.ensure(Index(List(("username", IndexType.Ascending)), unique = true)) map { r => 
      Ok 
     } 
     } recover { 
      case dex: DatabaseException => BadRequest(Json.toJson(GenericResponse("Failed"))) 

     } 
    } 

    } 
}.recoverTotal { e => 

    val errorResponse = BadRequest(Json.obj(
    "status" -> Messages("status.invalid"), 
    "message" -> Messages("error.generic.invalid_request"))) 

    Future.successful(errorResponse) 
} 

私がテストを実行しても、このときに取得していますエラー:Checked exception is invalid for this methodと、私の限られたからScala、Javaの知識と例外処理のしくみについては、スローする例外が宣言されなければならないことを理解しています。そのため、このエラーが発生する可能性があります。

ここから進んで、このシナリオをテストするにはどうすればよいですか?それが価値あるものであれば、apiメソッドは手動テストで期待どおりに動作します。

+0

https://github.com/cchantep/acolyte/tree/master/reactive-mongoをご覧ください。 – cchantep

答えて

0

この場合、Answerを使用する必要があります。ここ はREPLからの例です:

import org.mockito.Matchers.{eq => exact, _} 
import org.mockito.Mockito._ 
import org.mockito.invocation.InvocationOnMock 
import org.mockito.stubbing.Answer 
import org.scalatest.mock.MockitoSugar 

trait MyService { 
    def insert(v: String): String 
} 

val mk = MockitoSugar.mock[MyService] 

when(mk.insert(any())).thenAnswer(new Answer[String] { 
    def answer(invocation: InvocationOnMock): String = 
    throw new Exception("this should have never happened") 
}) 

mk.insert("test") 
// java.lang.Exception: this should have never happened 
//  at #worksheet#.$anon$1.answer(/dummy.sc:14) 
//  at #worksheet#.$anon$1.answer(/dummy.sc:13) 
//  at org.mockito.internal.stubbing.StubbedInvocationMatcher.answer(/dummy.sc:30) 
//  at #worksheet#.#worksheet#(/dummy.sc:87) 

編集:私たちのプロジェクトでは、我々はそのような場合にはあまり定型は次のように、そこの答えするFunctionNからの暗黙の型変換のセットを定義した:

implicit def function1ToAnswer[T, R](function: T => R)(implicit ct: ClassTag[T]): Answer[R] = new Answer[R] { 
    def answer(invocation: InvocationOnMock): R = invocation.getArguments match { 
    case Array(t: T, _*) => function(t) 
    case arr => fail(s"Illegal stubbing, first element of array ${arr.mkString("[", ",", "]")} is of invalid type.") 
    } 
} 

編集2:MockitoのFuturesでの作業については、ほとんどの言語機能のセマンティクスを考慮して、単体テストを簡略化するために発明した別の便利なラッパーもあります:

thenReturnは、元のメソッドに対して簡単で透過的です(既存の同期コードをテストでの修正が少なくても非同期に変換することもできます)。 thenFailはこれより少し小さいですが、この場合にはthenThrowを定義することはできません。暗黙的には適用されません。

+1

これはありがとうございます - 私は特に暗黙のコンバータが大好きです! 残念ながら、それは問題を完全には解決しませんでしたが、本当の解決策に向かって私を案内してくれたので非常に有益でした。これはずっと簡単でした。 私はその理由として答えをマークしました。また、コード例からいくつかのことを学びました。だから、ありがとう:-) –

+1

うれしい私は助けることができました!私は先物でフォークするための別の便利なユーティリティを提供するために私の答えを編集しました:) – Sergey

+0

非常に参考に - ありがとう –

関連する問題