Cómo ejecutar pruebas sobre el argumento que pasa un controlador a la vista en Play Framework

StackOverflow https://stackoverflow.com//questions/20005032

  •  20-12-2019
  •  | 
  •  

Pregunta

En nuestra aplicación de juego, cada función del controlador obtiene datos de la base de datos (o de alguna otra forma) y pasa estos valores al resultado.

def index = Action { implicit request =>
    val newsItems: List[String] = fetchNewsFromDB()
    Ok(views.html.home.index(newsItems))
  }

def fetchNewsFromDB() = List("Headline1", "Headline2")

Estoy escribiendo pruebas usando especificaciones (basadas en la documentación http://www.playframework.com/documentation/2.2.x/ScalaTest)

Según esta documentación por el controlador de la siguiente manera.En la próxima prueba quiero asegurarme de que la página de índice contenga un título.Hago esto comprobando si existe un div con la clase "título"

"Example Page#index" should {
    "should contain a headline" in {
      val controller = new TestController()
      val result: Future[SimpleResult] = controller.index().apply(FakeRequest())
      val bodyText: String = contentAsString(result)
      bodyText.toLowerCase must contain("<div class=\"headline\"")
    }
  }

Sin embargo, prefiero comprobar si la lista de artículos de noticias que el controlador pasa a la vista no está vacía.

¿Cuál es la mejor manera de hacer esto?¿Es posible hacer esto de forma genérica para la que se requieren pocas modificaciones de los controladores?

¿Fue útil?

Solución

Yo también estaba frustrado por no poder interceptar los parámetros en su camino hacia la plantilla y, de hecho, puede resultar extremadamente difícil incluso lograr que la plantilla se renderice. en absoluto en las pruebas si tiene mucho "estado" en sus páginas (por ejemplo, implícitos que proporcionan el objeto de usuario, ayudas de navegación, etc.).

Lo que terminé haciendo fue poner una "costura" adicional para la capacidad de prueba de mis controladores;en mis pruebas, yo extender el controlador bajo prueba, reemplazando la función de representación HTML con una simulada, que luego puedo usar para verificar los parámetros.

A continuación se muestra un ejemplo sencillo basado en su acción "noticias";En primer lugar, el responsable del tratamiento, que ya no es un object para que podamos extenderlo:

object Application extends ApplicationController

trait ApplicationController extends Controller {

  def newsAction = Action {
    Ok(renderNews("this is the news"))
  }

  def renderNews(s:List[String]):Html = html.sandbox(s)
}

El renderNews El método nos proporciona la importante "costura de prueba".Creo que también mejora la legibilidad de los métodos del controlador, lo cual es bueno :-)

Ahora, la prueba unitaria:

class ApplicationSpec extends Specification with Mockito {

  val mockedNewsRenderer = mock[List[String] => Html]

  val controller = new ApplicationController {
    override def renderNews(s:List[String]) = mockedNewsRenderer(s)
  }

  "Application News Controller" should {

    "Pass a non-empty list of news items to the template" in {
      val result = controller.newsAction(FakeRequest())

      status(result) must beEqualTo(200)

      val captor = ArgumentCaptor.forClass(classOf[List[String]])

      there was one(mockedNewsRenderer).apply(captor.capture())
      val theArgument = captor.getValue
      theArgument.isEmpty must beFalse
    }
  }
}

Creamos un simulacro para sustituir al renderNews función, extienda el controlador para que podamos sustituirlo (tenga en cuenta que no cambiamos nada más, por supuesto), y luego llame a la acción normalmente.Tenga en cuenta que todavía obtenemos un Play estándar Result para que aún podamos verificar los códigos de estado, etc., pero luego, podemos usar el Mockito verifica la funcionalidad integrada en Specs2, Juntos con Mockitos ArgumentCaptor instalación para afirmar que nuestra plantilla fue realmente llamada y que se le proporcionó una lista de cadenas no vacía.

Este enfoque ha funcionado bien para mí: permite obtener una cobertura de código realmente buena de sus controladores con pruebas unitarias de ejecución rápida y fáciles de escribir.

Otros consejos

You have a very good question and a very valid point on testing controllers, but I'm afraid it can't be done easily. The problem is that the views compile to Scala functions meaning when you call views.html.home.index(newsItems) it will return an object of Html, which already has the Html put together and compiled. If you would like to test what get's passed in you need to intercept it before the view is called.

To solve this you would have to rewrite your controllers, by moving all your business logic out of the controller and only have the necessary request handling code there. That would almost be easier to test.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top