mocking private variables in a function for testing Junit4

BRDroid :

I am writing a Junit4 test for a function which has Boolean variables which are set based on other functions. How can I mock these Boolean variable in my test case.

The function I am testing

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))
    }
}

This is how the values are set

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()
        }
    }
}

My test case

@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")
}

I want to be able to change values on operatorSigned and engineerSigned how can I do that.

Blundell :

Let's pretend the OPERATOR path of your code sets these booleans to 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")
}

(had to pretend because right now the code you shared only ever sets the booleans to true).

You are now unit testing the classes behaviour not testing how that behaviour is coded. For example, now if those booleans where refactored out for an Int value. This test would still pass without you having to touch it, that is a good thing!


Or if your code stays as is. You can test like this:

@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()
}

How to mock a static method (hint you don't, you move it to the edge of your system and worry about it later).

Your class right now:

class MyClass {

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

}

So you need to remove the static call, for another class that can do the static call as a dependency.

interface SignatureCompressor {
    fun compress(signature: String)
}

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

Now your class becomes:

class MyClass(private val compressor: SignatureCompressor) {

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

}

and you can mock the compressor:

 val cut = MyClass(mockk())

You also don't need the interface if you only have one implementation of compressing

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=7335&siteId=1
Recommended