🧠 From Leetcode to Android: The Practical Application of Test-Driven Development (TDD) in Business
"Writing tests is not a waste of time; it's to verify that our understanding of the business is correct."
1. Why Talk About TDD
In many Android projects, tests are often written after the development is completed. However, as business complexity grows and team collaboration increases, relying solely on "manual checks" is no longer sufficient to ensure logical stability.
Test-Driven Development (TDD) is a development approach where you write tests before implementing functionality. It requires developers to define expected inputs, outputs, and state transitions before writing the actual implementation.
However, applying TDD in Android scenarios is not straightforward— UI behavior is complex, states are diverse, and inputs are not fixed. Hence, we need to view it from a different perspective.
2. Understanding TDD Through Leetcode
Let's first look at a classic problem in algorithms:
Leetcode 105: Construct Binary Tree from Preorder and Inorder Traversal
/**
* Given two integer arrays preorder and inorder,
* where preorder is the preorder traversal of a binary tree
* and inorder is the inorder traversal of the same tree,
* construct the binary tree and return its root node.
*
* - Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
* - Output: [3,9,20,null,null,15,7]
*/
In this problem, the input (preorder, inorder) and output (tree structure) relationship is very clear. Each pair of input and output essentially serves as a "test case."
As long as all test cases pass, we can be confident that the implementation is correct. This captures the core idea of TDD.
3. Generating Test Samples: Using ChatGPT
For problems like this, we can leverage ChatGPT to quickly generate multiple test samples. Here is a simplified example:
// 1. Empty tree
preorder = []
inorder = []
// Output: []
// 2. Single node
preorder = [1]
inorder = [1]
// Output: [1]
// 3. Left subtree only
preorder = [3,2,1]
inorder = [1,2,3]
// Output: [3,2,null,1]
// 4. Right subtree only
preorder = [1,2,3]
inorder = [1,2,3]
// Output: [1,null,2,null,3]
ChatGPT can generate dozens of boundary and complex test cases at once, greatly improving test coverage. This is very valuable in real-world business scenarios: developers can focus on implementation logic instead of exhaustively enumerating test data.
4. The TDD Process in Android
Step 1️⃣: Define the Goal
Suppose we want to implement buildTree()
in the Algorithm layer:
class SolutionRepo {
fun buildTree(preorder: IntArray, inorder: IntArray): TreeNode? {
return null
}
}
Initially, it returns null
, meaning all tests will fail. This is expected in TDD.
Step 2️⃣: Write Test Cases
class SolutionRepoTest {
private val solution = SolutionRepo()
@Test
fun testBuildTree() {
// Iterate through all sample cases
(1..20).forEach { index ->
assertEquals(
expectedTree(index),
solution.buildTree(preorder(index), inorder(index))
)
}
}
}
Writing tests first is fine even if they all fail initially. The next step is to make the tests pass.
Step 3️⃣: Implement → Verify → Refactor
Developers can repeatedly run testBuildTree()
in the IDE. Once all test cases pass, the implementation satisfies all expected state transitions.
This is the TDD loop that minimizes risk and increases confidence:
Red → Green → Refactor Write failing tests → Make tests pass → Refactor code
5. Challenges of TDD in Android Business
🧩 1. Limited Test Coverage
Algorithm problems have clearly defined input-output relationships, but business logic often is not just "right or wrong." User operations are complex, data states are varied, and external dependencies are unpredictable. TDD cannot exhaustively cover all scenarios, so collaboration with product and QA teams is essential to define realistic state cases.
⚠️ Otherwise, developers may fall into the trap of "writing code just to pass tests."
🧩 2. UI Layer TDD Is Harder Than Backend
Backend inputs and outputs can be fully described with data, but Android also involves:
- UI states;
- User interactions;
- Lifecycle and asynchronous behavior.
Most teams focus on applying TDD in the logic layer (ViewModel / UseCase), abstracting UI behavior into state flows (StateFlow / LiveData), and asserting on the state transitions.
✅ The focus is on testing business logic, not UI.
6. The True Meaning of TDD
TDD is not about writing more tests or achieving 100% coverage. It is a process for verifying understanding.
It forces us to clarify "what is correct" before writing implementation.
In team collaboration, this mindset is often more valuable than the tests themselves. It allows:
- Product Managers → Define states and expected results;
- Developers → Validate logic correctness first;
- QA → Focus on edge cases and exceptions.
When everyone operates on the same “state transition map,” the entire product development chain is aligned.
7. Conclusion
Leetcode gives us deterministic problems; Android gives us complexity problems.
TDD does not solve everything, but it provides a method— to abstract order out of chaos.
"Define what is correct first, then implement it." This is the true significance of TDD in the business world.