كيفية تنفيذ الاختبارات على الوسيطة التي تقوم وحدة التحكم بتمريرها إلى العرض في Play Framework

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

  •  20-12-2019
  •  | 
  •  

سؤال

في تطبيق اللعب الخاص بنا، تقوم كل وظيفة تحكم بجلب البيانات من قاعدة البيانات (أو بطريقة أخرى) وتمرير هذه القيم إلى النتيجة

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

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

أنا أكتب اختبارات باستخدام المواصفات (استنادًا إلى الوثائق http://www.playframework.com/documentation/2.2.x/ScalaTest)

وفقا لهذه الوثائق من قبل وحدة التحكم على النحو التالي.في الاختبار التالي أريد التأكد من أن صفحة الفهرس تحتوي على عنوان رئيسي.أفعل ذلك عن طريق التحقق من وجود div بالفئة "headline"

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

ومع ذلك أفضل التحقق مما إذا كانت قائمة عناصر الأخبار التي تمررها وحدة التحكم إلى العرض غير فارغة.

ما هي أفضل طريقة للقيام بذلك؟هل من الممكن القيام بذلك بطريقة عامة تتطلب القليل من التعديل على وحدات التحكم؟

هل كانت مفيدة؟

المحلول

لقد شعرت أيضًا بالإحباط لأنني لم أتمكن من اعتراض المعلمات في طريقها إلى القالب - وفي الواقع قد يصبح من الصعب للغاية حتى عرض القالب على الاطلاق في الاختبارات إذا كان لديك الكثير من "الحالة" في صفحاتك (على سبيل المثال، العناصر الضمنية التي توفر كائن المستخدم، ومساعدي التنقل، وما إلى ذلك).

ما انتهى بي الأمر إلى فعله هو وضع "خط التماس" إضافي لقابلية الاختبار في وحدات التحكم الخاصة بي؛في اختباراتي انا يمتد وحدة التحكم قيد الاختبار، واستبدال وظيفة عرض HTML بوظيفة ساخرة، والتي يمكنني بعد ذلك استخدامها للتحقق من المعلمات.

فيما يلي مثال بسيط يعتمد على إجراء "الأخبار" الخاص بك؛أولاً، وحدة التحكم، التي لم تعد object حتى نتمكن من تمديده:

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

ال renderNews تعطينا هذه الطريقة "خط الاختبار" الأكثر أهمية.أعتقد أنه يعمل أيضًا على تحسين إمكانية قراءة أساليب التحكم أيضًا، وهو أمر لطيف :-)

والآن اختبار الوحدة:

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

نقوم بإنشاء نموذج وهمي للوقوف في renderNews قم بتوسيع وحدة التحكم حتى نتمكن من استبدالها (لاحظ أننا لا نغير أي شيء آخر عنها بالطبع)، ثم نستدعي الإجراء كالمعتاد.لاحظ أننا لا نزال نحصل على اللعب القياسي Result لذلك لا يزال بإمكاننا التحقق من رموز الحالة وما إلى ذلك، ولكن بعد ذلك، يمكننا استخدام يتحقق Mockito من الوظائف المضمنة في Specs2, ، معا مع موكيتو ArgumentCaptor منشأة للتأكد من أن القالب الخاص بنا قد تم استدعاؤه بالفعل، وأنه تم تزويده بقائمة غير فارغة من السلاسل.

لقد نجح هذا الأسلوب بشكل جيد بالنسبة لي - فهو يجعل من الممكن الحصول على تغطية جيدة للتعليمات البرمجية لوحدات التحكم الخاصة بك من خلال اختبارات الوحدة سريعة التشغيل وسهلة الكتابة.

نصائح أخرى

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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top