docs/truth_guide.md
[TOC]
Every subject class should extend
Subject and
follow the naming schema [ClassUnderTest]Subject. The Subject must also have a
constructor that accepts
FailureMetadata
and a reference to the object under test, which are both passed to the
superclass.
class NavControllerSubject private constructor(
metadata: FailureMetadata,
private val actual: NavController
) : Subject(metadata, actual) { }
The Subject class should also contain two static fields; a
Subject Factory
and anassertThat() shortcut method.
A subject Factory provides most of the functionality of the Subject by allowing
users to perform all operations provided in the Subject class by passing this
factory to about() methods. E.g:
assertAbout(navControllers()).that(navController).isGraph(x) where isGraph()
is a method defined in the Subject class.
The assertThat() shortcut method simply provides a shorthand method for making
assertions about the Subject without needing a reference to the subject factory.
i.e., rather than using
assertAbout(navControllers()).that(navController).isGraph(x) users can simply
useassertThat(navController).isGraph(x).
companion object {
fun navControllers(): Factory<NavControllerSubject, NavController> =
Factory<NavControllerSubject, NavController> { metadata, actual ->
NavControllerSubject(metadata, actual)
}
@JvmStatic
fun assertThat(actual: NavController): NavControllerSubject {
return assertAbout(navControllers()).that(actual)
}
}
When creating assertion methods for your custom Subject the names of these methods should follow the Truth naming convention.
To create assertion methods it is necessary to either delegate to an existing
assertion method by using Subject.check() or to provide your own failure
strategy by usingfailWithActual() or failWithoutActual().
When using failWithActual() the error message will display thetoString()
value of the Subject object. Additional information can be added to these error
messages by using fact(key, value) or simpleFact(value) where fact() will
be output as a colon separated key, value pair.
fun isGraph(@IdRes navGraph: Int) {
check("graph()").that(actual.graph.id).isEqualTo(navGraph)
}
// Sample Failure Message
value of : navController.graph()
expected : 29340
but was : 10394
navController was : {actual.toString() value}
fun isGraph(@IdRes navGraph: Int) {
val actualGraph = actual.graph.id
if (actualGraph != navGraph) {
failWithoutActual(
fact("expected id", navGraph.toString()),
fact("but was", actualGraph.toString()),
fact("current graph is", actual.graph)
)
}
}
// Sample Failure Message
expected id : 29340
but was : 10394
current graph is : {actual.graph.toString() value}
When testing expected successful assertions it is enough to simply call the assertion with verified successful actual and expected values.
private lateinit var navController: NavController
@Before
fun setUp() {
navController = NavController(
ApplicationProvider.getApplicationContext()
).apply {
navigationProvider += TestNavigator()
// R.navigation.testGraph == R.id.test_graph
setGraph(R.navigation.test_graph)
}
}
@Test
fun testGraph() {
assertThat(navController).isGraph(R.id.test_graph)
}
To test that expected failure cases you should use the assertThrows function from the AndroidX testutils module. The assertions.kt file contains two assertThrows functions. The second method, which specifically returns a TruthFailureSubject, should be used since it allows for validating additional information about the FailureSubject, particularly that it contains specific fact messages.
@Test
fun testGraphFailure() {
with(assertThrows {
assertThat(navController).isGraph(R.id.second_test_graph)
}) {
factValue("expected id").isEqualTo(R.id.second_test_graph.toString())
factValue("but was").isEqualTo(navController.graph.id.toString())
factValue("current graph is").isEqualTo(navController.graph.toString())
}
}