Mobiai write tests
Skill ArisGuimera/MobiAI-Core/skills/core/skills/mobiai-write-tests
Use when the user asks to write tests for mobile code, or after applying a fix that needs regression tests.From its SKILL.md
npx -y skills add ArisGuimera/MobiAI-Core --skill mobiai-write-testsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
9.5 KB, as published. Nobody here has run it
Write Tests
Write tests that cover a bug fix or new feature, following the project's existing patterns and platform conventions.
When to Use
- After applying a fix, to prevent regression
- User asks to add tests for specific code
- As part of the
mobiai-fix-issuepipeline
Note: If you're implementing a new feature or fix from scratch, consider using mobiai-mobile-tdd instead — it enforces writing tests FIRST (Red-Green-Refactor). This skill is for adding tests to existing code.
Pre-flight: check the Brain for relevant patterns
Standalone invocations only — skip this section when called from mobiai-fix-issue or mobiai-mobile-tdd, which run their own pre-flight or wrap this skill mid-flow.
If <repo>/.mobiai/brain/config.json exists, do a quick review pass before designing the test cases. A known workaround in the same area might shape what's worth asserting (the test should verify the workaround still works, not assume the fix is upstream).
Preferred — MCP tool (when mobiai-brain MCP server is registered):
Invoke mobile_review with default args. Focus on entries whose platform matches the project's platform and whose area overlaps with the system under test (datastore, networking, lifecycle, etc.). Run mobile_scan first if you don't already know the project's platform.
Fallback — CLI:
mobiai brain review --no-fail
If 1+ overdue entries match, mention them to the user before Step 1:
"Heads up — there are N overdue workaround(s) in <platform>/<area> that may shape what these tests need to cover: <title>. I'll proceed; let me know if you want to look at those first."
Then continue with Step 1. Skip silently when:
- The brain isn't initialized.
- No overdue entries match the area / platform of the code under test.
Pre-flight: check the Graph for code structure
Standalone invocations only — skip this section when called from mobiai-fix-issue or mobiai-mobile-tdd, which run their own Graph pre-flight or wrap this skill mid-flow.
The Graph helps locate the system under test, its callers, and nearby existing tests — useful before Step 1 (Understand What to Test) and Step 2 (Find Existing Test Patterns).
If <repo>/.mobiai/graph/index.json exists:
# Freshness — if "hace Xd" with X ≥ 1, suggest refresh (don't auto-run):
mobiai graph status
# Locate the symbol being tested:
mobiai graph search <ClassOrFunctionUnderTest>
# See how it's used in the codebase (informs which test cases matter):
mobiai graph callers <ClassOrFunctionUnderTest>
# Find existing test classes nearby (informs patterns and naming):
mobiai graph search Test --kind class --limit 20
The callers list reveals which call sites depend on the behavior — those are the cases worth covering. The existing-test search shows the project's actual test conventions (framework, naming, location).
If the index is ≥1 day old:
"El índice del Graph es de hace Xd. Si querés resultados frescos, corré
mobiai graph init."
Don't run init autonomously.
If .mobiai/graph/index.json does not exist and the project has .kt or .swift files:
"No veo el índice del Graph. Generalo con
mobiai graph inity arranco — sin él tengo que descubrir las convenciones de tests grepeando."
Don't run init autonomously.
Skip silently when:
- The project has no Kotlin/Swift files (Flutter or RN-only).
- You're testing pure Dart / JS / TS code (Graph doesn't index those in V1).
Workflow
Step 1: Understand What to Test
- Read the changed files to understand what was fixed or added
- Identify the testable unit — the method, class, or behavior that changed
- Define test cases:
- The specific behavior that was broken and is now fixed
- Edge cases related to the change
- Boundary conditions (null inputs, empty collections, max values)
Step 2: Find Existing Test Patterns
Before writing tests, find and read existing tests in the project:
Search for existing test files near the changed code:
- Use the Glob tool with patterns like
**/test/**/*Test*or**/*_test.* - Or use Grep to search for test classes:
class.*Testin test directories
Read existing tests to understand:
- Which test framework is used
- Naming conventions
- Mocking approach
- How dependencies are set up
- Where test files are located relative to source files
Step 3: Write Tests
Follow the project's existing patterns. If no patterns exist, follow platform defaults below.
Step 4: Run Tests
Run the test suite to verify:
- Your new tests pass
- Existing tests still pass (no regressions from the fix)
If tests fail, fix them. If existing tests fail and your fix caused the regression, fix that too.
Step 5: Capture in MobiAI Brain (if worth remembering)
Once tests pass, check whether <repo>/.mobiai/brain/config.json exists. If it does NOT, skip this step silently — not every project uses Brain.
If it does, decide whether this test is a reusable pattern worth saving as a testing_pattern entry. A test is worth saving when it captures a non-obvious mobile-specific gotcha — async/lifecycle timing, platform quirks, flaky-test workarounds, fixture patterns. Skip when the test is a routine assertion on business logic.
When it's worth saving, propose the save to the user first (one-line confirmation). Never invoke silently.
Preferred — MCP tool (if your client has the mobiai-brain MCP server registered, you'll see this tool in your toolbox):
Invoke mobile_save_testing with:
title: short pattern name, e.g."DataStore clear waits for empty emission"platform:android | ios | shared | kmp | flutter | react-nativearea: free-form, e.g."datastore" | "coroutines" | "xctest" | "maestro"files: array of repo-relative paths (test + system-under-test)body: Markdown with### Problem/### Solution/### Example(omit### Examplewhen the language doesn't fit)
Fallback — CLI (if MCP isn't configured):
mobiai brain save testing \
--title "<short pattern name, e.g. 'DataStore clear waits for empty emission'>" \
--platform <android|ios|shared|kmp|flutter|react-native> \
--area <free-form, e.g. datastore | coroutines | xctest | maestro> \
--files "<test_file>,<sut_file>" \
--body "### Problem
What goes wrong without this pattern (race, leak, false pass, etc.).
### Solution
The pattern itself, in one paragraph.
### Example
\`\`\`kotlin
// minimal code snippet
\`\`\`"
Skip the body's ### Example block on languages that don't fit. The fewer placeholders, the better — concrete pattern in the user's own words beats a generic template.
Platform Conventions
Android (Kotlin)
Default framework: JUnit 4 + MockK
Test location: Mirror source path under test directory
- Source:
app/src/main/java/com/example/feature/MyClass.kt - Test:
app/src/test/java/com/example/feature/MyClassTest.kt
Naming: Backtick-enclosed descriptive names
@Test
fun `calculateTotal returns zero when cart is empty`() { ... }
@Test
fun `formatPrice throws when amount is negative`() { ... }
Mocking: Use io.mockk (mockk, every, verify, coEvery for coroutines)
Coroutines: Use kotlinx-coroutines-test with runTest
Run tests:
./gradlew test<Flavor>DebugUnitTest --no-daemon
Rules:
- No Android framework in unit tests — use Robolectric only if absolutely needed
- Mock external dependencies (repositories, APIs, DAOs)
- Test ViewModels with
MainDispatcherRuleorDispatchers.setMain()
iOS (Swift)
Default framework: XCTest
Test location: Inside the test target
- Source:
MyApp/Feature/MyClass.swift - Test:
MyAppTests/Feature/MyClassTests.swift
Naming: test prefix + descriptive name
func testCalculateTotal_returnsZero_whenCartIsEmpty() { ... }
func testFormatPrice_throws_whenAmountIsNegative() { ... }
Run tests:
xcodebuild test -scheme <scheme> -destination 'platform=iOS Simulator,name=iPhone 15' -quiet
Flutter (Dart)
Default framework: flutter_test
Test location: test/ directory mirroring lib/
- Source:
lib/feature/my_class.dart - Test:
test/feature/my_class_test.dart
Naming: test() with descriptive strings
test('calculateTotal returns zero when cart is empty', () { ... });
group('formatPrice', () {
test('throws when amount is negative', () { ... });
});
Run tests:
flutter test
React Native (TypeScript/JavaScript)
Default framework: Jest
Test location: __tests__/ directory or co-located .test.ts files
Naming: describe + it blocks
describe('calculateTotal', () => {
it('returns zero when cart is empty', () => { ... });
});
Run tests:
npx jest
KMP (Kotlin Multiplatform)
Test location: shared/src/commonTest/kotlin/ for shared code
Run tests:
./gradlew :shared:testDebugUnitTest # Android target
./gradlew :shared:iosSimulatorArm64Test # iOS target
When Tests Are Not Possible
Set testsWritten=false if:
- The fix is in tightly coupled UI code with no way to unit test without massive refactoring
- The fix is a configuration change (manifest, plist, build file)
- The fix is purely a resource change (strings, layouts, assets)
Always explain why tests couldn't be written.