Command Line Tools
wheels test run
wheels test run
Section titled “wheels test run”Run TestBox tests for your Wheels application using the TestBox CLI integration.
Note: This command replaces the deprecated
wheels testcommand.
Prerequisites
Section titled “Prerequisites”Install TestBox CLI
Section titled “Install TestBox CLI”box install testbox-cli --globalSynopsis
Section titled “Synopsis”wheels test run [spec] [options]CommandBox Parameter Syntax
Section titled “CommandBox Parameter Syntax”This command supports multiple parameter formats:
- Named parameters:
name=value(e.g.,format=json,filter="User") - Flag parameters:
--flagequalsflag=true(e.g.,--coverageequalscoverage=true) - Flag with value:
--flag=valueequalsflag=value(e.g.,--format=json)
Parameter Mixing Rules:
ALLOWED:
- All named:
wheels test run format=json verbose=true - All flags:
wheels test run --verbose --coverage - Named + flags:
wheels test run format=json --coverage
NOT ALLOWED:
- Positional + named: Not applicable for this command (no positional parameters)
Recommendation: Use named parameters for specific values, flags for boolean options: wheels test run format=json --coverage
Description
Section titled “Description”The wheels test run command executes your application’s TestBox test suite with support, filtering, and various output formats. This is the primary command for running your application tests (as opposed to framework tests).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
type | string | app | Type of tests to run |
format | string | txt | Test output format: txt, junit, json |
bundles | string | - | The path or list of paths of the spec bundle CFCs to run and test ONLY |
directory | string | - | The directory to use to discover test bundles and specs to test |
recurse | boolean | true | Recurse the directory mapping or not |
verbose | boolean | true | Display extra details including passing and skipped tests |
servername | string | - | Server name for test execution |
filter | string | - | Filter tests by pattern or name |
labels | string | - | The list of labels that a suite or spec must have in order to execute |
coverage | boolean | false | Enable code coverage with FusionReactor |
Examples
Section titled “Examples”Run all tests
Section titled “Run all tests”wheels test runFilter tests by pattern
Section titled “Filter tests by pattern”# Named parameter (recommended for string values)wheels test run filter="User"wheels test run filter="test_user_validation"Run specific bundles
Section titled “Run specific bundles”# Named parameter (recommended)wheels test run bundles="tests.models"wheels test run bundles="tests.models,tests.controllers"Run tests with specific labels
Section titled “Run tests with specific labels”# Named parameter (recommended)wheels test run labels="unit"wheels test run labels="critical,auth"Generate coverage report
Section titled “Generate coverage report”# Flag (recommended for boolean)wheels test run --coverage
# OR namedwheels test run coverage=trueUse different output format
Section titled “Use different output format”# Named (recommended)wheels test run format=jsonwheels test run format=junit
# OR flag with valuewheels test run --format=jsonRun tests from specific directory
Section titled “Run tests from specific directory”# Named parameters (recommended)wheels test run directory="tests/specs"wheels test run directory="tests/specs/unit" recurse=falseVerbose output with coverage
Section titled “Verbose output with coverage”# Flags + named (recommended)wheels test run --verbose --coverage format=txt
# OR all namedwheels test run verbose=true coverage=true format=txtRun tests for different type
Section titled “Run tests for different type”# Named (recommended)wheels test run type=corewheels test run type=appTest Structure
Section titled “Test Structure”Standard test directory layout:
/tests/├── Application.cfc # Test configuration├── models/ # Model tests│ ├── UserTest.cfc│ └── ProductTest.cfc├── controllers/ # Controller tests│ ├── UsersTest.cfc│ └── ProductsTest.cfc├── views/ # View tests├── integration/ # Integration tests└── helpers/ # Test helpersWriting Tests
Section titled “Writing Tests”Model Test Example
Section titled “Model Test Example”component extends="wheels.Testbox" {
function run() { describe("User Model", function() {
beforeEach(function() { // Reset test data application.wirebox.getInstance("User").deleteAll(); });
it("validates required fields", function() { var user = model("User").new(); expect(user.valid()).toBeFalse(); expect(user.errors).toHaveKey("email"); expect(user.errors).toHaveKey("username"); });
it("saves with valid data", function() { var user = model("User").new( email="test@example.com", username="testuser", password="secret123" ); expect(user.save()).toBeTrue(); expect(user.id).toBeGT(0); });
it("prevents duplicate emails", function() { var user1 = model("User").create( email="test@example.com", username="user1" );
var user2 = model("User").new( email="test@example.com", username="user2" );
expect(user2.valid()).toBeFalse(); expect(user2.errors.email).toContain("already exists"); });
}); }
}Controller Test Example
Section titled “Controller Test Example”component extends="wheels.Testbox" {
function run() { describe("Products Controller", function() {
it("lists all products", function() { // Create test data var product = model("Product").create(name="Test Product");
// Make request var event = execute( event="products.index", renderResults=true );
// Assert response expect(event.getRenderedContent()).toInclude("Test Product"); expect(event.getValue("products")).toBeArray(); });
it("requires auth for create", function() { var event = execute( event="products.create", renderResults=false );
expect(event.getValue("relocate_URI")).toBe("/login"); });
}); }
}Test Configuration
Section titled “Test Configuration”/tests/Application.cfc
Section titled “/tests/Application.cfc”component { this.name = "WheelsTestingSuite" & Hash(GetCurrentTemplatePath());
// Use test datasource this.datasources["wheelstestdb"] = { url = "jdbc:h2:mem:wheelstestdb;MODE=MySQL" }; this.datasource = "wheelstestdb";
// Test settings this.testbox = { testBundles = "tests", recurse = true, format = "simple", labels = "", options = {} };}Reporters
Section titled “Reporters”txt (Default)
Section titled “txt (Default)”wheels test run format=txt- Plain txt output
- Good for CI systems
- No colors
wheels test run format=json√ tests.specs.functions.Example (3 ms)[Passed: 1] [Failed: 0] [Errors: 0] [Skipped: 0] [Suites/Specs: 1/1]
√ Tests that DummyTest √ is Returning True (1 ms)╔═════════════════════════════════════════════════════════════════════╗║ Passed ║ Failed ║ Errored ║ Skipped ║ Bundles ║ Suites ║ Specs ║╠═════════════════════════════════════════════════════════════════════╣║ 1 ║ 0 ║ 0 ║ 0 ║ 1 ║ 1 ║ 1 ║╚═════════════════════════════════════════════════════════════════════╝wheels test run format=junit- JUnit XML format
- For CI integration
- Jenkins compatible
Filtering Tests
Section titled “Filtering Tests”By Bundle
Section titled “By Bundle”# Run only model testswheels test run bundles=tests.models
# Run multiple bundleswheels test run bundles=tests.models,tests.controllersBy Label
Section titled “By Label”component extends="wheels.Testbox" labels="label title"# Run only critical testswheels test run labels="label title"
# Run auth OR api testswheels test run labels=auth,apiBy Name Filter
Section titled “By Name Filter”# Run tests matching patternwheels test run filter="user"wheels test run filter="validate*"Benefits:
- Faster execution
- Better CPU utilization
- Finds concurrency issues
Code Coverage
Section titled “Code Coverage”Generate coverage reports:
wheels test run --coverage coverageOutputDir=coverage/View report:
open coverage/index.htmlTest Helpers
Section titled “Test Helpers”Create reusable test utilities:
component {
function createTestUser(struct overrides={}) { var defaults = { email: "test#CreateUUID()#@example.com", username: "user#CreateUUID()#", password: "testpass123" };
return model("User").create( argumentCollection = defaults.append(arguments.overrides) ); }
function loginAs(required user) { session.userId = arguments.user.id; session.isAuthenticated = true; }
}Database Strategies
Section titled “Database Strategies”Transaction Rollback
Section titled “Transaction Rollback”function beforeAll() { transaction action="begin";}
function afterAll() { transaction action="rollback";}Database Cleaner
Section titled “Database Cleaner”function beforeEach() { queryExecute("DELETE FROM users"); queryExecute("DELETE FROM products");}Fixtures
Section titled “Fixtures”function loadFixtures() { var users = deserializeJSON( fileRead("/tests/fixtures/users.json") );
for (var userData in users) { model("User").create(userData); }}CI/CD Integration
Section titled “CI/CD Integration”GitHub Actions
Section titled “GitHub Actions”- name: Run tests run: | wheels test run format=junit outputFile=test-results.xml
- name: Upload results uses: actions/upload-artifact@v4 with: name: test-results path: test-results.xmlPre-commit Hook
Section titled “Pre-commit Hook”#!/bin/bashecho "Running tests..."wheels test run labels=unit
if [ $? -ne 0 ]; then echo "Tests failed. Commit aborted." exit 1fiCommon Issues
Section titled “Common Issues”Out of Memory
Section titled “Out of Memory”# Increase memorybox server set jvm.heapSize=1024box server restartTest Pollution
Section titled “Test Pollution”- Use
beforeEach/afterEach - Reset global state
- Use transactions
Flaky Tests
Section titled “Flaky Tests”- Avoid time-dependent tests
- Mock external services
- Use fixed test data
See Also
Section titled “See Also”- wheels generate test - Generate test files