【问题标题】:mocking private variables in a function for testing Junit4在用于测试 Junit4 的函数中模拟私有变量
【发布时间】:2020-02-13 15:37:28
【问题描述】:

我正在为一个函数编写一个 Junit4 测试,该函数具有基于其他函数设置的布尔变量。如何在我的测试用例中模拟这些布尔变量。

我正在测试的功能

private var operatorSigned = false
private var engineerSigned = false


override fun onValidationSucceeded() {
    if (operatorSigned && engineerSigned) {
        sendQualityControlCheck()
    } else {
        view.showToastMessage(app.getString(R.string.quality_control_signatures_not_complete))
    }
}

这是设置值的方式

override fun signatureSigned(name: String, svgSignature: String, bitmapSignature: Bitmap, signatureType: SignatureType) {
    val svgSignatureGzipped = CompressionTools.gzipCompress(svgSignature)
    when (signatureType) {
        SignatureType.OPERATOR -> {
            operatorSignature = QualityControlSignature(svgSignatureGzipped, DateTime())
            operatorSigned = true
            view.operatorSignatureSigned()
        }
        SignatureType.ENGINEER -> {
            engineerSignature = QualityControlSignature(svgSignatureGzipped, DateTime())
            engineerSigned = true
            engineerName = name
            view.engineerSignatureSigned()
        }
    }
}

我的测试用例

@Test
fun `must show toast message when onValidationSucceeded is called and operatorSigned is false`() {
    `when`(app.getString(R.string.quality_control_signatures_not_complete)).thenReturn("Operator and Engineer signature required")
    presenter.onValidationSucceeded()
    verify(view).showToastMessage("Operator and Engineer signature required")
}

我希望能够更改 operatorSigned 和 EngineerSigned 的值,我该怎么做。

【问题讨论】:

  • 它们是如何设置的?在您发布的代码中,它们始终为false。 (即如果它们在其他函数中设置,则调用其他函数进行设置)。
  • 但它们基于太多其他参数
  • 更新了我的问题
  • 对我来说这似乎是一个类设计问题。如果您将签名代码作为自己的类并将其注入,则可能更容易测试
  • 不要尝试测试“代码”。单元测试验证代码的public observable期望的行为

标签: java android unit-testing kotlin junit


【解决方案1】:

让我们假设您的代码的 OPERATOR 路径将这些布尔值设置为 false:

@Test
fun `must show toast message when onValidationSucceeded is called and signature is Operator`() {
    // Given
    signatureSigned("unusedName", "unusedSig", null, SignatureType.OPERATOR) 
`when`(app.getString(R.string.quality_control_signatures_not_complete)).thenReturn("Operator and Engineer signature required")
    // When
    presenter.onValidationSucceeded()
    // Then
    verify(view).showToastMessage("Operator and Engineer signature required")
}

(不得不假装,因为现在您共享的代码只会将布尔值设置为 true)。

您现在正在对类行为进行单元测试,而不是测试如何对行为进行编码。例如,现在如果那些布尔值被重构为 Int 值。无需您触摸它仍然可以通过此测试,这是一件好事


或者,如果您的代码保持原样。你可以这样测试:

@Test
fun `must show toast message when onValidationSucceeded is called and has not been signature signed`() {
    // Given
    // We haven't signature signed (see verify)
   `when`(app.getString(R.string.quality_control_signatures_not_complete)).thenReturn("Operator and Engineer signature required")
    // When
    presenter.onValidationSucceeded()
    // Then
    verify(view).showToastMessage("Operator and Engineer signature required")
    verify(view, never()).operatorSignatureSigned()
    verify(view, never()).engineerSignatureSigned()
}

如何模拟一个静态方法(提示你不要,你把它移到你系统的边缘然后再担心它)。

你现在的班级:

class MyClass {

    override fun signatureSigned(name: String, svgSignature: String, bitmapSignature: Bitmap, signatureType: SignatureType) {
        val svgSignatureGzipped = CompressionTools.gzipCompress(svgSignature)
        ...
    }

}

所以你需要删除静态调用,另一个类可以将静态调用作为依赖项。

interface SignatureCompressor {
    fun compress(signature: String)
}

class GZipSignatureCompressor : SignatureCompressor {
    override fun compress(signature: String) {
        return CompressionTools.gzipCompress(signature)
    } 
}

现在你的班级变成了:

class MyClass(private val compressor: SignatureCompressor) {

    override fun signatureSigned(name: String, svgSignature: String, bitmapSignature: Bitmap, signatureType: SignatureType) {
        val svgSignatureGzipped = compressor.compress(svgSignature)
        ...
    }

}

你可以模拟压缩器:

 val cut = MyClass(mockk())

如果你只有一种压缩实现,你也不需要接口

【讨论】:

  • 谢谢,这是一个完美的想法,但有一个问题,在 signatureSigned 函数中,我如何模拟 val svgSignatureGzipped = CompressionTools.gzipCompress(svgSignature) 它给了我一个错误,即 svgSignatureGzipped 为空
  • 将静态方法调用包装成一个类GZipCompressor或其他东西,然后将其作为类的依赖项传递。
  • 不明白该怎么做对不起
  • 我会把它添加到答案中
猜你喜欢
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-02
  • 2023-04-04
  • 2018-08-24
  • 1970-01-01
相关资源
最近更新 更多