невозможно написать тестовую спецификацию для метода контроллера - PullRequest
0 голосов
/ 27 марта 2019

Я тестирую этот метод моего класса контроллеров. Метод выполняет несколько асинхронных запросов к базе данных и, в зависимости от результата, Redirect s запрос. Успешность предыдущего запроса к базе данных определяет, должен ли быть выполнен следующий запрос.

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, который вызывается методом verifyUser в цикле for

Чтобы проверить код, я написал следующую спецификацию

"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,test@test.com),1,true,Some(PasswordInfo(someHasher,somePassword,Some(someSalt))))),ExternalUserProfile(test@test.com,ln,fn,Some(somePassword))))
    returning mocked token UserToken(11111111-1111-1111-1111-111111111111,11111111-1111-1111-1111-111111111111,UserKeys(1,test@test.com,LoginInfo(credentials,test@test.com),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 [Пользователь])). thenReturn ( Будущее{ println (s "подтверждение поддельного пользователя $ {testEnv.user}") Некоторые из них (testEnv.user) } )

У меня мало сомнений. вопрос 1) я не издеваюсь testEnv.controller. Могу ли я по-прежнему использовать when в одном из методов testEnv.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 значение?

1 Ответ

0 голосов
/ 27 марта 2019

мой плохой.Я понимаю, что не могу использовать 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)
    }
  )
...