The original article was published on April 24, 2025.
Hello, I'm Munetoshi Ishikawa, a mobile client developer for the LINE messaging app.
This article is the latest installment of our weekly series "Improving code quality". For more information about the Weekly Report, please see the first article.
Double-edged tests
Let's say we have a data model FooModel and a class FooModelLogger that logs its information. The FooModelLogger decorates the string properties of FooModel to make them more readable in logs. In the implementation below, constructor arguments are defined to allow the injection of dependent logic for testing.
class FooModel(val title: String, val description: String)
class FooModelLogger(
private val textLogger: TextLogger = TextLogger(),
private val joinString: String.(Any?) -> String = String::plus,
private val decorate: (String) -> String = { text -> LogTextUtility.decorateText(text, "*") },
private val getTitle: FooModel.() -> String = { this.title },
) {
fun log(model: FooModel) {
val titleToLog = model.getTitle()
val decoratedTitle = decorate(titleToLog)
val combinedOutput = decoratedTitle.joinString(model.description)
textLogger.log(combinedOutput)
}
}
object LogTextUtility {
fun decorateText(text: String, decoration: String): String = ...
}
By allowing the injection of dependent code in this way, unit tests can focus solely on the logic contained directly within FooModelLogger.
@Test
fun `logs title and description with a normal FooModelObject`() {
val mockTextLogger: TextLogger = mock()
val mockJoinString: String.(Any?) -> String = { _ -> this + "MockDescription" }
val mockDecorate: (String) -> String = { "@$it@" }
val mockGetTitle: FooModel.() -> String = { "MockTitle" }
val subject = FooModelLogger(
textLogger = mockTextLogger,
joinString = mockJoinString,
decorate = mockDecorate,
getTitle = mockGetTitle
)
val fooModel = FooModel("RealTitle", "RealDescription")
subject.log(fooModel)
verify(mockTextLogger).log("@MockTitle@MockDescription")
}
Is there any problem with this code?
In a nutshell
Injecting too much logic into tests can complicate them and may lead to missing verification of interactions.
Keywords: unit test, test double, injection