Как выполнить модульное тестирование различных экземпляров классов типов для Numeric? - PullRequest
0 голосов
/ 23 ноября 2018

Допустим, у меня есть два экземпляра класса типов Numeric.

class Money(c: String, x: Long, y: Int)
class Quantity(c: String, x: Long, y: Int)
implicit val numericMoney: Numeric[Money] = new Numeric[Money]
implicit val numericQuantity: Numeric[Quantity] = new Numeric[Quantity]

Деньги и количество должны вести себя одинаково в числовом экземпляре.У меня есть тесты scalaTest, которые проверяют, что деньги ведут себя правильно.

например,

import implicits.NumericMoney.numericMoney._

class MoneyOpsSpec extends WordSpec with Matchers {

  val max = Money("", Long.MaxValue, 999999999)
  val min = Money("", Long.MinValue, -999999999)

  "A Money object" when {
    "zero" should {
      "be neutral element under addition" in {
        zero + Money("", 15, 50) should ===(Money("", 15, 50))
        Money("", 15, 50) + zero should ===(Money("", 15, 50))
      }
      "be neutral element under subtraction" in {
        zero - Money("", 15, 50) should ===(Money("", -15, -50))
        Money("", 15, 50) - zero should ===(Money("", 15, 50))
      }
      "be invariant under negation" in {
        -zero should ===(zero)
      }
    }
  }
}

Quantity спецификация должна выполняться таким же образом.Могу ли я реализовать общую спецификацию и использовать Money и Quantity в качестве входных данных для этой спецификации?Или у scalaTest или specs2 есть что-то, чтобы убедиться, что экземпляр класса Tymeric ведет себя правильно?Я могу легко переключать рамки тестирования.

Ответы [ 2 ]

0 голосов
/ 23 ноября 2018

Могу ли я реализовать общую спецификацию и использовать Деньги и Количество в качестве входных данных для этой спецификации?

Конечно.Просто примите неявное в качестве аргумента конструктора.Не проверено, но должно быть приблизительно (с минимальными изменениями):

abstract class NumOpsSpec[T](implicit num: Numeric[T], tag: ClassTag[T]) extends WordSpec with Matchers {
  import num._

  val max: T
  val min: T
  val someElement: T

  s"A ${tag.runtimeClass.simpleName} object" when {
    "zero" should {
      "be neutral element under addition" in {
        zero + someElement should ===(someElement)
        someElement + zero should ===(someElement)
      }
      "be neutral element under subtraction" in {
        zero - someElement should ===(- someElement)
        someElement - zero should ===(someElement)
      }
      "be invariant under negation" in {
        -zero should ===(zero)
      }
    }
  }
}

class MoneyOpsSpec extends NumOpsSpec[Money] {
  override val max = Money("", Long.MaxValue, 999999999)
  override val min = Money("", Long.MinValue, -999999999)
  override val someElement = Money("", 15, 50)
}

class QuantityOpsSpec extends NumOpsSpec[Quantity] {
  override val max = ???
  override val min = ???
  override val someElement = ???
}

Вы также можете посмотреть https://github.com/typelevel/discipline для проверки законов типов классов в целом.

0 голосов
/ 23 ноября 2018

Я думаю, что вам нужно создать абстрактные методы для тестирования различных операций и использовать их с обоими объектами.напримерчтобы проверить сложение

  def testAddition[T](a: T, b: T, expectedResult: T)(implicit n: Numeric[T]) = {
    n.plus(a, b) ==== expectedResult
  }

, вы можете вызвать этот метод с помощью Money или Quantity

testAddition(Money(1, 1), Money(2, 2), Money(3, 3))
testAddition(Quantity(1, 1), Quantity(2, 2), Quantity(3, 3))
...