diff --git a/formula-test/src/main/java/com/instacart/formula/test/TestExtensions.kt b/formula-test/src/main/java/com/instacart/formula/test/TestExtensions.kt
index 61c993cb..3b630eec 100644
--- a/formula-test/src/main/java/com/instacart/formula/test/TestExtensions.kt
+++ b/formula-test/src/main/java/com/instacart/formula/test/TestExtensions.kt
@@ -40,8 +40,22 @@ fun withSnapshot(
return observer.values().last()
}
+/**
+ *
+ * Creates a test formula for a specific [IFormula] instance.
+ *
+ * ```kotlin
+ * class FakeUserFormula : UserFormula {
+ * override val implementation = testFormula(
+ * initialOutput = User(
+ * name = "Fake user name",
+ * )
+ * )
+ * }
+ * ```
+ */
fun IFormula.testFormula(
initialOutput: Output,
): TestFormula {
- return TestFormula(initialOutput, key = { this.key(it) })
+ return TestFormula(this, initialOutput)
}
\ No newline at end of file
diff --git a/formula-test/src/main/java/com/instacart/formula/test/TestFormula.kt b/formula-test/src/main/java/com/instacart/formula/test/TestFormula.kt
index a517441c..ca0d561c 100644
--- a/formula-test/src/main/java/com/instacart/formula/test/TestFormula.kt
+++ b/formula-test/src/main/java/com/instacart/formula/test/TestFormula.kt
@@ -3,69 +3,73 @@ package com.instacart.formula.test
import com.instacart.formula.Action
import com.instacart.formula.Evaluation
import com.instacart.formula.Formula
+import com.instacart.formula.IFormula
import com.instacart.formula.Snapshot
+import com.instacart.formula.test.utils.RunningInstanceManager
import java.util.concurrent.atomic.AtomicLong
/**
- * Test formula is used to provide a fake formula implementation. It allows you to [send][output]
- * output updates and [inspect/interact][input] with input.
+ * Test formula is used to replace a real formula with a fake implementation. This allows you to:
+ * - Verify that parent passes correct inputs. Take a look at [input].
+ * - Verify that parent deals with output changes correctly. Take a look at [output]
+ *
+ *
+ * ```kotlin
+ * // To replace a real formula with a fake one, we need first define the interface
+ * interface UserFormula : IFormula {
+ * data class Input(val userId: String)
+ * data class Output(val user: User?)
+ * }
+ *
+ * // Then, we can create a fake implementation
+ * class FakeUserFormula : UserFormula {
+ * override val implementation = testFormula(
+ * initialOutput = Output(user = null)
+ * )
+ * }
+ *
+ * // Then, in our test, we can do the following
+ * @Test fun `ensure that account formula passes user id to user formula`() {
+ * val userFormula = FakeUserFormula()
+ * val accountFormula = RealAccountFormula(userFormula)
+ * accountFormula.test().input(AccountFormula.Input(userId = "my-user-id"))
+ *
+ * userFormula.implementation.input {
+ * Truth.assertThat(this.userId).isEqualTo("my-user-id")
+ * }
+ * }
+ * ```
*/
-abstract class TestFormula :
- Formula, Output>() {
-
- companion object {
- /**
- * Initializes [TestFormula] instance with [initialOutput].
- */
- operator fun invoke(
- initialOutput: Output,
- key: (Input) -> Any? = { null }
- ): TestFormula {
- return object : TestFormula() {
- override fun initialOutput(): Output = initialOutput
-
- override fun key(input: Input): Any? = key(input)
- }
- }
- }
+class TestFormula internal constructor(
+ private val parentFormula: IFormula,
+ private val initialOutput: Output,
+) : Formula, Output>() {
data class State