Skip to content

Add a recipe for custom build types and product flavors - #313

Merged
DanielJette merged 2 commits into
mainfrom
docs/131-build-types-and-flavors
Sep 25, 2026
Merged

DanielJette merged 2 commits into
mainfrom
docs/131-build-types-and-flavors

Conversation

@DanielJette

@DanielJette DanielJette commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

What does this change accomplish?

Build types and product flavors have no docs page, and flavor has returned no results in docs search in 2023, 2024 and 2025. Two users in #131 worked out the configuration themselves and asked for it to be documented.

Fixes #131
Relates to #238

How have you achieved it?

  • New recipe recipes/23-build-types-and-flavors.md.
  • Describes the inference in GradleProjectExtensions.kt: the first install…Debug / install…DebugAndroidTest task alphabetically, and applicationId plus the debug build type suffix (flavor suffixes are ignored).
  • Groovy and Kotlin DSL examples setting installTask, installAndroidTestTask, applicationPackageId and testPackageId together.
  • Notes that install tasks are task names, not paths, since the plugin resolves :<moduleName>:<task>.
  • Explains which settings stop the tests starting (install tasks, testPackageId) and which only affect screenshotPull / screenshotClear (applicationPackageId).
  • Verification with testifySettings and -Pverbose=true.
  • For nested modules (Improve error messages #238), sets moduleName to the full module path so the plugin finds the install tasks, with running the install tasks by hand as a fallback.

Scope of Impact and Testing instructions

Documentation only; no library or plugin changes, so no CHANGELOG entry. Built locally with yarn build from docs/. No broken links. Behaviour checked against TestifyExtension.kt, GradleProjectExtensions.kt and ScreenshotTestTask.kt.

Each commit includes [skip ci] so CI doesn't run for this docs-only change.

Notice

Warning

This change must keep main in a shippable state; it may be shipped without further notice.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AgUU49S4wSWd7vhJS7kEmU

Document how the Gradle plugin infers install tasks and package IDs, why
flavored and custom build type projects fail with "Unable to find
instrumentation info", and the four settings to configure together.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgUU49S4wSWd7vhJS7kEmU

@AndroidTestifyBot AndroidTestifyBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes requested

Accurate page — the inference table matches GradleProjectExtensions exactly, and the testifySettings sample output reproduces the real println block's field order and alignment. Two changes.

1. Lead with moduleName for nested modules

The nested-module section recommends running install tasks by hand. There's a better fix: the lookup is findByPath(":${settings.moduleName}:${settings.installAndroidTestTask}"), and moduleName is user-settable — so

testify {
    moduleName "feature:login"
}

makes the path resolve to :feature:login:installDebugAndroidTest and restores the automatic dependency. It also feeds the testifyModule resValue and the ./gradlew $moduleName:screenshotPull hints in error messages, which come out correct with the full path too.

Please make that the primary recommendation, with manual install tasks as the fallback.

2. Hedge the instrumentation error string

INSTRUMENTATION_STATUS: Error=Unable to find instrumentation info… is a platform message, not a Testify one, and it's what readers will paste into a search box. Please prefix it with "an error like this", the same treatment #321 gives its Hilt error.

Verified correct

  • installTask / installAndroidTestTask inference, including "first alphabetically" — tasks.names is a SortedSet.
  • That the inferred package IDs exclude product-flavor suffixes — applicationTargetPackageId only reads defaultConfig.applicationId and the debug build type.
  • testifySettings printing applicationPackageId as targetPackageId.
  • -Pverbose=true, and that screenshotTest/screenshotRecord dependsOn the install tasks.
  • Issue #238 is real, open, and exactly about this findByPath failure. The "skips installing without an error" claim is right — getInstallDebugAndroidTestTask(project)?.let { } swallows the null.

flavorDimensions = ["backend"] is the current AGP form and reads fine against an AGP 9 baseline — no change suggested unless you target an older minimum.

Reviewed by Claude on behalf of @DanielJette.

@AndroidTestifyBot AndroidTestifyBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

Both requested changes are in, and the moduleName section went further than I asked.

moduleName now leads, with the mechanism explained

The plugin looks for the install tasks at :<moduleName>:<task name>, and moduleName defaults to the module's own name, without its parent directories.

Verified: TestifySettings.create does extension.moduleName ?: project.name, and Gradle's project.name for :feature:login is login. So the inferred path really is :login:installGoogleMockDebugAndroidTest, which doesn't exist — and getInstallDebugAndroidTestTask(project)?.let { } swallows the null, hence the silent skip. Setting moduleName "feature:login" makes findByPath resolve. Manual installs are correctly demoted to a fallback.

The Groovy/Kotlin spelling is right in both tabs: moduleName has no is prefix, so both DSLs use the same name.

The error string is now attributed, not just hedged

The message comes from Android rather than Testify, and you'll see an error like this:

Better than what I asked for — telling readers the message isn't Testify's is more useful than a bare "an error like this".

New claim, verified

Testify runs the tests with adb shell am instrument using testPackageId, and reads screenshots from the device using applicationPackageId.

Correct on both halves: ScreenshotTestTask builds .argument("$testPackageId/$testRunner"), while ScreenshotPullTask and DeviceUtilities use runAs(targetPackageId) and interpolate targetPackageId into the SD card path. The follow-on — that a wrong applicationPackageId still lets tests run but sends screenshotPull/screenshotClear to the wrong app — follows directly and is right.

Re-verified from the previous round

Inference table, "first alphabetically" (tasks.names is a SortedSet), flavor suffixes correctly excluded from the inferred IDs, testifySettings printing targetPackageId, -Pverbose=true, and issue #238.

Docs build verified locally: exit 0, zero warnings, individually and combined.

Reviewed by Claude on behalf of @DanielJette.

@DanielJette
DanielJette merged commit 040c9f4 into main Sep 25, 2026
@DanielJette
DanielJette deleted the docs/131-build-types-and-flavors branch September 25, 2026 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

How to use testify with custom build type?

2 participants