Reputation: 4388
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.
Upvotes: 2
Views: 635
Reputation: 76496
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
Upvotes: 2