Issue
I am currently trying to write Unit tests for my code, and I am running into the problem of needing context for some of my classes (use-cases?).
Here is an example of the code:
In the class, I use the string resource to return a result.
class testClass {
fun compareNumbers(numberOne: Int, numberTwo: Int, context: Context): String {
var message = ""
when {
numberOne > numberTwo -> message = context.getString(R.string.numberOne)
numberOne < numberTwo -> message = context.getString(R.string.numberTwo)
numberOne == numberTwo -> message = context.getString(R.string.tie)
}
return message
}
}
In the view model:
fun declareWinner(context: Context) {
val result = testClass.compareNumbers(numberOne, numberTwo, context)
updateResult(result) //updates the result to a database
}
I thought this would have been a good way of separating the functions from one another and not making my view model messy. Plus I need functions like the compareNumbers in many VMs, so I thought it was more reusable. However, I am making a Unit test for this and it doesn't work as simply as I would like.
Is there a better way to do this or just try to make the context using mockito?
Solution
Your testClass
shouldn't be aware of the Context
. The role of a Use Case is to contain the business logic, but definitely not to be aware of any UI or Android Framework classes :[
You could try to inject already localized strings into this method, or even better, return an enum or sealed class and let the ViewModel
map this enum to the actual string resource, separating the concerns: your business logic class doesn't need to know about how to present the result to the UI, and ViewModel
doesn't need to know about the business logic, just how to map the result to the UI representation, kinda:
sealed class CompareResult {
object NumberOneWins : CompareResult()
object NumberTwoWins : CompareResult()
object Tie : CompareResult()
}
class TestClass {
fun compareNumbers(numberOne: Int, numberTwo: Int): CompareResult {
return when {
numberOne > numberTwo -> CompareResult.NumberOneWins
numberOne < numberTwo -> CompareResult.NumberTwoWins
else -> CompareResult.Tie
}
}
}
// In your ViewModel
fun declareWinner() {
val result = testClass.compareNumbers(numberOne, numberTwo)
val message = when (result) {
is CompareResult.NumberOneWins -> context.getString(R.string.numberOne)
is CompareResult.NumberTwoWins -> context.getString(R.string.numberTwo)
is CompareResult.Tie -> context.getString(R.string.tie)
}
updateResult(message)
}
Resulting in painless unit testing without the Context
, and ViewModel
becomes easier to test as well - you can mock compareNumbers
method to return a specific CompareResult
, and then just verify that updateResult
was called with a correct string.
Answered By - Yahor Barkouski
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.