مرحبا هبر! لا يكفي كتابة كود جيد. ما زلنا بحاجة إلى تغطيتها باختبارات وحدة جيدة. في المقال الأخير ، قمت بإنشاء خادم ويب بسيط. الآن سأحاول كتابة عدد الاختبارات. منتظم ، قائم على الملكية ، وسخر منه. لمزيد من التفاصيل ، مرحبا بكم تحت القط.
المحتوى
- سكالا التعليمية: الجزء 1 - لعبة الأفعى
- سكالا التعلم: الجزء 2 - صحيفة تودو مع إمكانية تحميل الصور
- مقياس التعلم: الجزء 3 - اختبارات الوحدة
الروابط
مصادر
الصور صورة عامل الإرساء
وهكذا بالنسبة لاختبارات الوحدة هناك حاجة إلى 3 ليبس.
- مكتبة لإنشاء الاختبارات
- المكتبة التي ستولد بيانات الاختبار
- مكتبة من شأنها أن تسخر من الأشياء
لقد استخدمت مكتبة ScalaTest لإنشاء الاختبارات
"org.scalatest" %% "scalatest" % "3.2.0" % Test
لقد استخدمت ScalaCheck لإنشاء بيانات اختبار للاختبار القائم على الخاصية .
"org.scalacheck" %% "scalacheck" % "1.14.3" % Test
وامتداد يجمع بين ScalaTest + ScalaCheck ScalaTestPlusScalaCheck
"org.scalatestplus" %% "scalacheck-1-14" % "3.2.0.0" % Test
لقد استخدمت ScalaMock للسخرية من الأشياء
"org.scalamock" %% "scalamock" % "4.4.0" % Test
فئة بسيطة تمثل نوع السلسلة المعبأة (غير الفارغة). سنختبرها الآن.
package domain.common
sealed abstract case class FilledStr private(value: String) {
def copy(): FilledStr = new FilledStr(this.value) {}
}
object FilledStr {
def apply(value: String): Option[FilledStr] = {
val trimmed = value.trim
if (trimmed.nonEmpty) {
Some(new FilledStr(trimmed) {})
} else {
None
}
}
}
إنشاء فصل دراسي لاختباراتنا
class FilledStrTests extends AnyFlatSpec with should.Matchers with ScalaCheckPropertyChecks {
}
نقوم بإنشاء طريقة للتحقق من أنه عند إنشاء فصلنا من نفس الأسطر ، سوف نتلقى نفس البيانات.
"equals" should "return true fro equal value" in {
val str = "1234AB"
val a = FilledStr(str).get
val b = FilledStr(str).get
b.equals(a) should be(true)
}
في الاختبار الأخير ، اختبأنا في سلسلة تم إنشاؤها يدويًا. الآن دعونا نجري اختبارًا باستخدام البيانات التي تم إنشاؤها. سنستخدم نهجًا قائمًا على الخصائص يتم من خلاله اختبار خصائص الوظيفة ، بحيث نتلقى بيانات الإخراج هذه باستخدام بيانات الإدخال هذه.
"constructor" should "save expected value" in {
forAll { s: String =>
// . .
whenever(s.trim.nonEmpty) {
val a = FilledStr(s).get
a.value should be(s)
}
}
}
يمكنك تكوين منشئ بيانات الاختبار بشكل صريح لاستخدام البيانات التي نحتاجها فقط. على سبيل المثال مثل هذا:
//
val evenInts = for (n <- Gen.choose(-1000, 1000)) yield 2 * n
//
forAll (evenInts) { (n) => n % 2 should equal (0) }
لا يمكنك أيضًا تمرير المولد الخاص بنا بشكل صريح ، ولكن يمكنك تحديد تأثيره عبر Arbitrary بحيث يتم تمريره تلقائيًا كمولد للاختبارات. على سبيل المثال مثل هذا:
implicit lazy val myCharArbitrary = Arbitrary(Gen.oneOf('A', 'E', 'I', 'O', 'U'))
val validChars: Seq[Char] = List('X')
// Arbitrary[Char] .
forAll { c: Char => validChars.contains(c) }
يمكنك أيضًا إنشاء كائنات معقدة باستخدام Arbitrary.
case class Foo(intValue: Int, charValue: Char)
val fooGen = for {
intValue <- Gen.posNum[Int]
charValue <- Gen.alphaChar
} yield Foo(intValue, charValue)
implicit lazy val myFooArbitrary = Arbitrary(fooGen)
forAll { foo: Foo => (foo.intValue < 0) == && !foo.charValue.isDigit }
لنحاول الآن كتابة اختبار بجدية أكبر. سوف نسخر من تبعيات TodosService. يستخدم مستودعين 2 ويستخدم المستودع بدوره فكرة تجريدية على معاملة UnitOfWork. دعونا نختبر أبسط طريقة لها.
def getAll(): F[List[Todo]] =
repo.getAll().commit()
الذي يستدعي المستودع فقط ، ويبدأ المعاملة فيه لقراءة قائمة Todo ، وينهيها ويعيد النتيجة. أيضًا في الاختبار ، بدلاً من F [_] ، يتم وضع Id monad ، والذي يقوم ببساطة بإرجاع القيمة المخزنة فيه.
class TodoServiceTests extends AnyFlatSpec with MockFactory with should.Matchers {
"geAll" should " " in {
// .
implicit val tr = mock[TodosRepositoryContract[Id, Id]]
implicit val ir = mock[InstantsRepositoryContract[Id]]
implicit val uow = mock[UnitOfWorkContract[Id, List[Todo], Id]]
// . implicit
val service= new TodosService[Id, Id]()
// Id Todo
val list: Id[List[Todo]] = List(Todo(1, "2", 3, Instant.now()))
// getAll uow 1
(tr.getAll _).expects().returning(uow).once()
// commit 1
(uow.commit _).expects().returning(list).once()
// getAll
//
service.getAll() should be(list)
}
}
تبين أن اختبارات الكتابة في Scala كانت ممتعة للغاية ، واتضح أن ScalaCheck و ScalaTest و ScalaMock مكتبات جيدة جدًا. بالإضافة إلى مكتبة لإنشاء API tapir والمكتبة لخادم http4s ومكتبة لتيارات fs2. حتى الآن ، تسبب البيئة والمكتبات الخاصة بـ Scala مشاعر إيجابية فقط في داخلي. آمل أن يستمر هذا الاتجاه.