wheels test run

Run TestBox tests for your application with advanced features.

Synopsis

wheels test run [spec] [options]

Description

The wheels test run command executes your application's TestBox test suite with support for watching, filtering, and various output formats. This is the primary command for running your application tests (as opposed to framework tests).

Options

Option
Description
Default

filter

Filter tests by pattern or name

group

Run specific test group

--coverage

Generate coverage report (boolean flag)

false

reporter

Test reporter format: console, junit, json, tap

console

--watch

Watch for file changes and rerun tests (boolean flag)

false

--verbose

Verbose output (boolean flag)

false

--fail-fast

Stop on first test failure (boolean flag)

false

Examples

Run all tests

wheels test run

Filter tests by pattern

wheels test run filter="User"
wheels test run filter="test_user_validation"

Watch mode

wheels test run --watch

Run specific test group

wheels test run group="unit"
wheels test run group="integration"

Generate coverage report

wheels test run --coverage

Use different reporter

wheels test run reporter=json
wheels test run reporter=junit
wheels test run reporter=tap

Stop on first failure

wheels test run --fail-fast

Verbose output with coverage

wheels test run --verbose --coverage reporter=console

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 helpers

Writing Tests

Model Test Example

component extends="testbox.system.BaseSpec" {

    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="[email protected]",
                    username="testuser",
                    password="secret123"
                );
                expect(user.save()).toBeTrue();
                expect(user.id).toBeGT(0);
            });
            
            it("prevents duplicate emails", function() {
                var user1 = model("User").create(
                    email="[email protected]",
                    username="user1"
                );
                
                var user2 = model("User").new(
                    email="[email protected]",
                    username="user2"
                );
                
                expect(user2.valid()).toBeFalse();
                expect(user2.errors.email).toContain("already exists");
            });
            
        });
    }

}

Controller Test Example

component extends="testbox.system.BaseSpec" {

    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

/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,
        reporter = "simple",
        labels = "",
        options = {}
    };
}

Watch Mode

Watch mode reruns tests on file changes:

wheels test run --watch

Output:

[TestBox Watch] Monitoring for changes...
[TestBox Watch] Watching: /tests, /models, /controllers

[14:23:45] Change detected: models/User.cfc
[14:23:45] Running tests...

✓ User Model > validates required fields (12ms)
✓ User Model > saves with valid data (45ms)
✓ User Model > prevents duplicate emails (23ms)

Tests: 3 passed, 0 failed
Time: 80ms

[TestBox Watch] Waiting for changes...

Reporters

Simple (Default)

wheels test run reporter=simple
  • Colored console output

  • Shows progress dots

  • Summary at end

Text

wheels test run reporter=text
  • Plain text output

  • Good for CI systems

  • No colors

JSON

wheels test run reporter=json
{
    "totalDuration": 523,
    "totalSpecs": 25,
    "totalPass": 24,
    "totalFail": 1,
    "totalError": 0,
    "totalSkipped": 0
}

JUnit

wheels test run reporter=junit outputFile=results.xml
  • JUnit XML format

  • For CI integration

  • Jenkins compatible

TAP

wheels test run reporter=tap
  • Test Anything Protocol

  • Cross-language format

Filtering Tests

By Bundle

# Run only model tests
wheels test run bundles=models

# Run multiple bundles
wheels test run bundles=models,controllers

By Label

it("can authenticate", function() {
    // test code
}).labels("auth,critical");
# Run only critical tests
wheels test run labels=critical

# Run auth OR api tests
wheels test run labels=auth,api

By Name Filter

# Run tests matching pattern
wheels test run filter="user"
wheels test run filter="validate*"

Exclude Patterns

# Skip slow tests
wheels test run excludes="*slow*,*integration*"

Parallel Execution

Run tests in parallel threads:

wheels test run threads=4

Benefits:

  • Faster execution

  • Better CPU utilization

  • Finds concurrency issues

Code Coverage

Generate coverage reports:

wheels test run --coverage coverageOutputDir=coverage/

View report:

open coverage/index.html

Test Helpers

Create reusable test utilities:

// /tests/helpers/TestHelper.cfc
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

Transaction Rollback

function beforeAll() {
    transaction action="begin";
}

function afterAll() {
    transaction action="rollback";
}

Database Cleaner

function beforeEach() {
    queryExecute("DELETE FROM users");
    queryExecute("DELETE FROM products");
}

Fixtures

function loadFixtures() {
    var users = deserializeJSON(
        fileRead("/tests/fixtures/users.json")
    );
    
    for (var userData in users) {
        model("User").create(userData);
    }
}

CI/CD Integration

GitHub Actions

- name: Run tests
  run: |
    wheels test run reporter=junit outputFile=test-results.xml
    
- name: Upload results
  uses: actions/upload-artifact@v2
  with:
    name: test-results
    path: test-results.xml

Pre-commit Hook

#!/bin/bash
# .git/hooks/pre-commit

echo "Running tests..."
wheels test run labels=unit

if [ $? -ne 0 ]; then
    echo "Tests failed. Commit aborted."
    exit 1
fi

Performance Tips

  1. Use labels for fast feedback

    wheels test run labels=unit  # Fast
    wheels test run labels=integration  # Slow
  2. Parallel execution

    wheels test run threads=4
  3. Watch specific directories

    wheels test run tests/models --watch
  4. Skip slow tests during development

    wheels test run excludes="*integration*"

Common Issues

Out of Memory

# Increase memory
box server set jvm.heapSize=1024
box server restart

Test Pollution

  • Use beforeEach/afterEach

  • Reset global state

  • Use transactions

Flaky Tests

  • Avoid time-dependent tests

  • Mock external services

  • Use fixed test data

See Also

Last updated

Was this helpful?