I am trying to use Slather to generate test coverage reports for Xcode projects and hook it into CI.
Experiment 1 - Using xcodebuild test (Succeed)
> xcodebuild test \
-workspace mobile-ios.xcworkspace \
-scheme mobile-ios \
-destination "platform=iOS Simulator,name=iPhone 17,OS=26.0"
generates DerivedData folder with test coverage info inside.
Next Slather succeed as well.
> bundle exec slather
Slathering...
Slathered
Experiment 2 - Using tuist test (Failed)
Here is my Project.swift
import Foundation
import ProjectDescription
let swiftVersion = try! String(
contentsOfFile: ".swift-version",
encoding: .utf8
).trimmingCharacters(in: .whitespacesAndNewlines)
let project = Project(
name: "mobile-ios",
settings: .settings(
base: [
"SWIFT_VERSION": .string(swiftVersion),
]
),
targets: [
.target(
name: "mobile-ios",
destinations: .iOS,
product: .app,
bundleId: "dev.tuist.mobile-ios",
infoPlist: .extendingDefault(
with: [
"UILaunchScreen": [
"UIColorName": "",
"UIImageName": "",
]
]
),
buildableFolders: [
"mobile-ios/Sources",
"mobile-ios/Resources",
],
dependencies: [
.external(name: "WhisperKit"),
.external(name: "MLXLLM"),
.external(name: "MLXLMCommon"),
]
),
.target(
name: "mobile-iosTests",
destinations: .iOS,
product: .unitTests,
bundleId: "dev.tuist.mobile-iosTests",
infoPlist: .default,
buildableFolders: [
"mobile-ios/Tests"
],
dependencies: [.target(name: "mobile-ios")]
),
],
schemes: [
.scheme(
name: "mobile-ios",
shared: true,
buildAction: .buildAction(
targets: [
.target("mobile-ios")
]
),
testAction: .targets(
[
.testableTarget(target: "mobile-iosTests")
],
options: .options(
coverage: true,
codeCoverageTargets: [
.target("mobile-ios")
]
)
)
)
]
)
Currently,
> tuist test --device "iPhone 17"
generated DerivedData folder, however, inside it is missing many test coverage related info, for example ~/Library/Developer/Xcode/DerivedData/mobile-ios-xxx/Build/ProfileData folder.
This caused Slather failed
> bundle exec slather
Slathering...
No coverage directory found.
Are you sure your project is generating coverage? Make sure you enable code coverage in the Test section of your Xcode scheme.
Did you specify your Xcode scheme? (--scheme or 'scheme' in .slather.yml)
If you're using a workspace, did you specify it? (--workspace or 'workspace' in .slather.yml)
If you use a different Xcode configuration, did you specify it? (--configuration or 'configuration' in .slather.yml)
bundler: failed to load command: slather (/Users/hongbo-miao/.rbenv/versions/3.4.7/bin/slather)
/Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/slather-2.8.5/lib/slather/project.rb:244:in 'Slather::Project#profdata_coverage_dir': No coverage directory found. (StandardError)
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/slather-2.8.5/lib/slather/project.rb:542:in 'Slather::Project#find_binary_files'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/slather-2.8.5/lib/slather/project.rb:472:in 'Slather::Project#configure_binary_file'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/slather-2.8.5/lib/slather/project.rb:347:in 'Slather::Project#configure'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/slather-2.8.5/lib/slather/command/coverage_command.rb:62:in 'CoverageCommand#execute'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/clamp-1.3.3/lib/clamp/command.rb:66:in 'Clamp::Command#run'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/clamp-1.3.3/lib/clamp/subcommand/execution.rb:18:in 'Clamp::Subcommand::Execution#execute'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/clamp-1.3.3/lib/clamp/command.rb:66:in 'Clamp::Command#run'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/clamp-1.3.3/lib/clamp/command.rb:140:in 'Clamp::Command.run'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/slather-2.8.5/bin/slather:17:in '<top (required)>'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/bin/slather:25:in 'Kernel#load'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/bin/slather:25:in '<top (required)>'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/lib/bundler/cli/exec.rb:58:in 'Kernel.load'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/lib/bundler/cli/exec.rb:58:in 'Bundler::CLI::Exec#kernel_load'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/lib/bundler/cli/exec.rb:23:in 'Bundler::CLI::Exec#run'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/lib/bundler/cli.rb:455:in 'Bundler::CLI#exec'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/lib/bundler/vendor/thor/lib/thor/command.rb:28:in 'Bundler::Thor::Command#run'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in 'Bundler::Thor::Invocation#invoke_command'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/lib/bundler/vendor/thor/lib/thor.rb:527:in 'Bundler::Thor.dispatch'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/lib/bundler/cli.rb:35:in 'Bundler::CLI.dispatch'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/lib/bundler/vendor/thor/lib/thor/base.rb:584:in 'Bundler::Thor::Base::ClassMethods#start'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/lib/bundler/cli.rb:29:in 'Bundler::CLI.start'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/exe/bundle:28:in 'block in <top (required)>'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/lib/bundler/friendly_errors.rb:117:in 'Bundler.with_friendly_errors'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/lib/ruby/gems/3.4.0/gems/bundler-2.5.11/exe/bundle:20:in '<top (required)>'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/bin/bundle:25:in 'Kernel#load'
from /Users/hongbo-miao/.rbenv/versions/3.4.7/bin/bundle:25:in '<main>'
error: Recipe `test-coverage` failed on line 28 with exit code 1
Here is the difference
How to let tuist test generate test coverage data properly? Thanks! ![]()
