替换仅在 Scala 中的特定单元测试中使用的方法
Replace a method for usage only in a particular unit tests in Scala
是否可以使用版本 2.11 和 scalatest 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 returns 是一个常量,而不是随机数。
我知道,我可以在 getEncodedKey 方法中使用额外的输入参数 (testFlag) 或在 getSalt 方法中使用全局变量来获得解决方案。但是,我想知道是否有一种方法可以不触及 getEncodedKey 并且只在一个单元测试中实现一些东西。
一个简单的方法是创建一个像 SaltGenerator
这样的特征,然后实现你的方法使用的特征,这将允许你创建一个 SatlGenerator
其中 returns测试时保持不变。
例如:
trait SaltGenerator {
def getSalt(length): String
}
class KeyHasher(saltGenerator: SaltGenerator) {...}
然后,在编写测试时,只需创建 returns 常量的生成器:
val saltGenerator = new SaltGenerator {
def getSalt(length): String = ???
}
虽然您可以找到一种方法来模拟现有方法,但这总是很棘手并且难以维护。如果您不想更新您的代码,另一种方法是接收 SecureRandom
作为构造函数参数,但在测试端完成您想要的事情并不那么简单。
您可以制作一个 class 来扩展您的原始 class 并且只覆盖您想要的方法,例如:
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
但这并不理想...您遇到了随机代码的主要问题之一 - 难以测试。一种解决方案是将随机生成器放入新的 class/object/whatever 和 extend/inject 中,这样您就可以在测试中覆盖它。像这样:
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
是否可以使用版本 2.11 和 scalatest 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 returns 是一个常量,而不是随机数。
我知道,我可以在 getEncodedKey 方法中使用额外的输入参数 (testFlag) 或在 getSalt 方法中使用全局变量来获得解决方案。但是,我想知道是否有一种方法可以不触及 getEncodedKey 并且只在一个单元测试中实现一些东西。
一个简单的方法是创建一个像 SaltGenerator
这样的特征,然后实现你的方法使用的特征,这将允许你创建一个 SatlGenerator
其中 returns测试时保持不变。
例如:
trait SaltGenerator {
def getSalt(length): String
}
class KeyHasher(saltGenerator: SaltGenerator) {...}
然后,在编写测试时,只需创建 returns 常量的生成器:
val saltGenerator = new SaltGenerator {
def getSalt(length): String = ???
}
虽然您可以找到一种方法来模拟现有方法,但这总是很棘手并且难以维护。如果您不想更新您的代码,另一种方法是接收 SecureRandom
作为构造函数参数,但在测试端完成您想要的事情并不那么简单。
您可以制作一个 class 来扩展您的原始 class 并且只覆盖您想要的方法,例如:
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
但这并不理想...您遇到了随机代码的主要问题之一 - 难以测试。一种解决方案是将随机生成器放入新的 class/object/whatever 和 extend/inject 中,这样您就可以在测试中覆盖它。像这样:
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