Come eseguire test sull'argomento secondo cui un controller passa alla vista in Play Framework

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

  •  20-12-2019
  •  | 
  •  

Domanda

Nel nostro applicazione di riproduzione ogni funzione controller recupera i dati dal database (o un altro modo) e passa questi valori al risultato

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

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

Sto scrivendo test usando le specificazioni (in base alla documentazione http://www.playframework.com / documentazione / 2.2.x / scalatest )

Secondo questa documentazione tramite controller come segue.Nel test successivo voglio assicurarmi che la pagina dell'indice contiene un titolo.Lo faccio controllando se esiste un div con la classe "Titolo"

"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\"")
    }
  }
.

Comunque preferirei controllare se l'elenco newitchem che il controller passa alla vista è non vuoto.

Qual è il modo migliore per farlo? È possibile questo in modo generico per il quale è richiesta una piccola modifica dei controller?

È stato utile?

Soluzione

Anche io è stato frustrato da non poter intercettare i parametri sulla loro strada per il modello - e infatti può diventare estremamente difficile anche ottenere il modello per rendere a tutti nei test se tu Avere un sacco di "stato" nelle tue pagine (ad esempio, impliciti che forniscono l'oggetto utente, aiutanti di navigazione ecc.).

Quello che ho finito per fare stava mettendo in una "cucitura" in più per la testimoniabilità nei miei controller; Nei miei test, I Estendi il controller in Test, sostituisce la funzione di rendering HTML con uno deriso, che posso quindi utilizzare per verificare i parametri.

Ecco un semplice esempio in base alla tua azione "Notizie"; Innanzitutto, il controller, che non è più un object in modo da poterlo estendere:

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)
}
.

Il metodo renderNews ci dà la "cucitura di prova" importanti. Penso che anche in realtà migliora la leggibilità dei metodi del controller, che è bello: -)

Ora, il test dell'unità:

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
    }
  }
}
.

Creiamo un finto in stand-in per la funzione renderNews, estendere il controller in modo che possiamo sostituirlo (nota che non cambiamo nient'altro circa ovviamente), quindi chiamiamo l'azione normale. Nota che otteniamo ancora un giocatore standard Result in modo da poter controllare ancora i codici di stato ecc., Ma allora, possiamo usare il Mockito Verifica funzionalità che è incorporato in specips2 , insieme a impianto ArgumentCaptor di mockito per affermare che il nostro modello è stato effettivamente chiamato, e che è stato fornito con un elenco non vuoto di stringhe.

Questo approccio ha funzionato bene per me - consente di ottenere una copertura del codice davvero buona dei controller con test di unità a funzionamento rapido e facile da scrivere.

Altri suggerimenti

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top