Замените метод для использования только в определенных модульных тестах в Scala - PullRequest
0 голосов
/ 14 октября 2019

Можно ли заменить метод, используемый только в определенных модульных тестах в Scala, используя версию 2.11 и скалярную версию 3.0.4?

Это мой сценарий: у меня есть метод

import java.security.SecureRandom
import org.bouncycastle.util.encoders.Hex

class KeyHasher extends Serializable {

  // getSalt returns a random number that servers as salt for the actual hash algorithm  
  def getSalt(length): String = {
    val salt: Array[Byte] = new Array[Byte](length)
    secureRandom.nextBytes(salt)
    Hex.toHexString(hashedKey)
  }

  def getEncodedKey(actualKey: String): String = {
  ...
  val salt = getSalt() 
  ...
  return applyHash(salt) // apply a hash algorithm using a salt
  }

}

Для конкретного модульного теста я хотел бы убедиться, что метод getSalt возвращает константу, а не случайное число.

Я знаю, что я мог бы использовать дополнительный входной параметр (testFlag) в методе getEncodedKey или глобальномпеременная в методе getSalt, чтобы получить решение для этого. Однако я хотел знать, есть ли способ не трогать getEncodedKey и реализовывать что-либо только в одном модульном тесте.

Ответы [ 2 ]

1 голос
/ 14 октября 2019

Простой подход состоит в том, чтобы просто создать черту наподобие SaltGenerator, а затем реализовать ту, которая используется вашим методом, это позволит вам создать SatlGenerator, который возвращает константу во время тестирования.

Например:

trait SaltGenerator {
  def getSalt(length): String
}

class KeyHasher(saltGenerator: SaltGenerator) {...}

Затем, при написании теста, просто создайте генератор, который возвращает константу:

val saltGenerator = new SaltGenerator {
  def getSalt(length): String = ???
}

В то время как вы сможете найти способ смоделировать существующийметод, который всегда хитрый и трудно поддерживать. Если вы не хотите обновлять свой код, другой способ - получить SecureRandom в качестве аргумента конструктора, но на тестовой стороне будет не так просто выполнить желаемое.

0 голосов
/ 14 октября 2019

Вы можете создать класс, который расширяет ваш исходный класс и переопределяет только те методы, которые вы хотите, например:

class DummyClass(x: Int) {
  def doSomething(): String = "xyz"

  def doSomethingElse(): Int = x * 2
}

class DummyClass2(x: Int) extends DummyClass(x) {
  override def doSomething(): String = "abc"
}

val a = new DummyClass(3)
val b = new DummyClass2(3)

println(a.doSomething())     // xyz
println(a.doSomethingElse()) // 6
println(b.doSomething())     // abc
println(b.doSomethingElse()) // 6

( смотрите здесь в прямом эфире )

или:

class DummyClass(x: Int) {
  def doSomething(): String = "xyz"

  def doSomethingElse(): Int = x * 2
}

object DummyClass2 extends DummyClass(3) {
  override def doSomething(): String = "abc"
}

val a = new DummyClass(3)
val b = DummyClass2

println(a.doSomething())     // xyz
println(a.doSomethingElse()) // 6
println(b.doSomething())     // abc
println(b.doSomethingElse()) // 6

( смотрите в прямом эфире здесь )

Это не идеально, хотя ... вы столкнулись с одной из основных проблем со случайным кодом- это сложно проверить. Одним из решений может быть помещение вашего генератора случайных чисел в новый класс / объект / что угодно и расширение / внедрение, чтобы вы могли переопределить его в тестах. Как то так:

import javax.inject.Inject

import scala.util.Random

class Generator {
  def rand = Random.nextInt()
}

class Dummy @Inject()(num: Int, gen: Generator) {
  def doSomething(): Int = num * gen.rand
}

// ---------------
//   ACTUAL CODE
// ---------------

val generator = new Generator
val x = new Dummy(3, generator)
println(x.doSomething()) // something
println(x.doSomething()) // something different

// ---------------
//    TEST CODE
// ---------------

val nonRandomGenerator = new Generator {
  override def rand: Int = 4
}
val y = new Dummy(3, nonRandomGenerator)
println(y.doSomething()) // 12
println(y.doSomething()) // 12
...