无法为控制器的方法编写测试规范

问题描述 投票:0回答:1

我正在测试我的控制器类的这个方法。该方法执行一些异步数据库查询,并根据结果,Redirects请求。先前数据库查询的成功确定是否需要执行下一个查询。

def verifyUser(token:String) = Action.async {
     implicit request => {
       println("verifyUser action called with token: " + token) //TODOM - add proper handling and response

       val result:Future[Result] = for{tokenOption:Option[UserToken] <- userTokenRepo.findOne(UserTokenKey(UUID.fromString(token)))  //generator 1 - get token from database
                                    userOption:Option[User] <- if (tokenOption.isDefined) {println(s"received tokenOption ${tokenOption}");userRepo.findOne(tokenOption.get.userKeys)} else {Future.successful(None)} //generator2. found token, look for corresponding user to which the token belongs
                                    modifiedUser:Option[User] <- if (userOption.isDefined) {println(s"received userOption ${userOption}");confirmSignupforUser(userOption.get)} else Future.successful(None) //generator 3. found user and token. Update profile
                                    deletedToken:Option[UserTokenKey] <- if(modifiedUser.isDefined) {println(s"received modified ${modifiedUser}");userTokenRepo.delete(UserTokenKey(UUID.fromString(token)))} else Future.successful(None)
       }
         yield { //check if we have user and token and modified user here. If any is missing, return error else success
           println("db query results tokenOption: "+tokenOption+", userOption: "+userOption+" : modifiedUserOption: "+modifiedUser+", deletedToken: "+deletedToken)
           if(tokenOption.isDefined && userOption.isDefined && modifiedUser.isDefined && deletedToken.isDefined)
              Redirect("http://localhost:9000/home"+";signup=success")//TODOM - pick from config
           else
             if(tokenOption.isEmpty)
             Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
           else if(userOption.isEmpty)
             Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
           else if(modifiedUser.isEmpty)
             Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
           else //this shouldn't happen. Unexpected
             Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config
         }
       result.recover { case x => {
         println("Future failed in validateUserSession. Recovering. Returning Internal Server Error" + x)
        }
       }
       result //returning Future[Result]
     }
   }

控制器还有一个方法confirmSignupforUser,它由for循环中的verifyUser方法调用

为了测试代码,我编写了以下规范

"verify token method" should {
    "work " in {
      val testEnv = new TestEnv(components.configuration)
      when(testEnv.mockUserTokenRepository.findOne(ArgumentMatchers.any[UserTokenKey])).thenReturn(
        Future{
          println(s"returning mocked token ${testEnv.userToken}")
          Some(testEnv.userToken)}
      )

      when(testEnv.mockUserRepository.findOne(ArgumentMatchers.any[UserKeys])).thenReturn(Future{
        println(s"returning mocked user ${testEnv.user}")
        Some(testEnv.user)
      })

      when(testEnv.controller.confirmSignupforUser(ArgumentMatchers.any[User])).thenReturn(
        Future{
          println(s"confirming mocked user ${testEnv.user}")
          Some(testEnv.user)
        }
      )

      when(testEnv.mockUserTokenRepository.delete(ArgumentMatchers.any[UserTokenKey])).thenReturn(
        Future{
          println(s"returning mocked token key ${testEnv.userTokenKey}")
          Some(testEnv.userTokenKey)
        }
      )


     val request = FakeRequest("POST", s"ws/users/signup/${testEnv.mockHelperMethods.getUniqueID()}")
      println("sending request", request)

    val resultFuture:Future[Result] = testEnv.controller.verifyUser(testEnv.mockHelperMethods.getUniqueID().toString()).apply(request)
      val responseBody = contentAsString(resultFuture)
      println(s"received response ${responseBody}")
      1 mustBe 1
    }
  }

我的测试是抛出null指针异常。

created TestEnv with configuration...

    confirming user: null
    returning mocked user User(11111111-1111-1111-1111-111111111111,UserProfile(Some(InternalUserProfile(LoginInfo(credentials,[email protected]),1,true,Some(PasswordInfo(someHasher,somePassword,Some(someSalt))))),ExternalUserProfile([email protected],ln,fn,Some(somePassword))))
    returning mocked token UserToken(11111111-1111-1111-1111-111111111111,11111111-1111-1111-1111-111111111111,UserKeys(1,[email protected],LoginInfo(credentials,[email protected]),fn,ln),2019-03-27T17:08:43.861Z,true)

    java.lang.NullPointerException was thrown.
    java.lang.NullPointerException
        at controllers.UserController.confirmSignupforUser(UserController.scala:442)

似乎导致问题的代码片段是

def confirmSignupforUser(user:User):Future[Option[User]] = {
    println("confirming user: "+user)
  ...
}

上面的代码是从我的规范中调用的(testEnv.controller.confirmSignupforUser(ArgumentMatchers.any [User]))。thenReturn(Future {println(s“确认模拟用户$ {testEnv.user}”)一些(testEnv) .user)})

我几乎没有怀疑。问题1)我不是在嘲笑testEnv.controller。我还可以在whentestEnv.controller)的一种方法中使用testEnv.controller.confirmSignupforUser(ArgumentMatchers.any[User])吗?

问题2)我是否正确在for循环中,userTokenRepo.findOne应该返回模拟值Some(testEnv.userToken)。这应该是使用userRepo.findOne(tokenOption.get.userKeys),它应该返回模拟值Some(testEnv.user)。这应该用在confirmSignupforUser(userOption.get)?问题3)为什么confirmSignupforUser得到null值?

mockito scalatest playframework-2.6
1个回答
0
投票

我的错。我意识到我不能使用when并传递controller的方法,因为我不是在嘲笑控制器。当测试向前移动时,我删除了以下行

//don't need this
when(testEnv.controller.confirmSignupforUser(ArgumentMatchers.any[User])).thenReturn(
    Future{
      println(s"confirming mocked user ${testEnv.user}")
      Some(testEnv.user)
    }
  )
© www.soinside.com 2019 - 2024. All rights reserved.