| # Adding custom Truth subjects |
| |
| [TOC] |
| |
| ## Custom truth subjects |
| |
| Every subject class should extend |
| [Subject](https://truth.dev/api/latest/com/google/common/truth/Subject.html) and |
| follow the naming schema `[ClassUnderTest]Subject`. The Subject must also have a |
| constructor that accepts |
| [FailureMetadata](https://truth.dev/api/latest/com/google/common/truth/FailureMetadata.html) |
| and a reference to the object under test, which are both passed to the |
| superclass. |
| |
| ```kotlin |
| class NavControllerSubject private constructor( |
| metadata: FailureMetadata, |
| private val actual: NavController |
| ) : Subject(metadata, actual) { } |
| ``` |
| |
| ### Subject factory |
| |
| The Subject class should also contain two static fields; a |
| [Subject Factory](https://truth.dev/api/latest/com/google/common/truth/Subject.Factory.html) |
| and an`assertThat()` 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 |
| use`assertThat(navController).isGraph(x)`. |
| |
| ```kotlin |
| 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) |
| } |
| } |
| ``` |
| |
| ### Assertion methods |
| |
| When creating assertion methods for your custom Subject the names of these |
| methods should follow the |
| [Truth naming convention](https://truth.dev/faq#assertion-naming). |
| |
| 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 using`failWithActual()` or `failWithoutActual()`. |
| |
| When using `failWithActual()` the error message will display the`toString()` |
| 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. |
| |
| ```kotlin |
| 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} |
| ``` |
| |
| ```kotlin |
| 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} |
| ``` |
| |
| ## Testing |
| |
| When testing expected successful assertions it is enough to simply call the |
| assertion with verified successful actual and expected values. |
| |
| ```kotlin |
| 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](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:testutils/testutils-truth/src/main/java/androidx/testutils/assertions.kt) |
| 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. |
| |
| ```kotlin |
| @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()) |
| } |
| } |
| ``` |
| |
| ## Helpful resources |
| |
| [Truth extension points](https://truth.dev/extension.html) |