๐Ÿ”ท Core trusted

testbox-assertions

Use this skill when using the TestBox $assert object for xUnit-style assertions: isTrue, isEqual, includes, isEmpty, key, instanceOf, throws, between, closeTo, lengthOf, match, null, typeOf, and others; registering custom assertion functions with addAssertions(); or using BoxLang dynamic assertion methods (assertIsTrue, assertBetween, etc.).

$ npx skills add coldbox/skills/testbox/assertions
$ coldbox ai skills install coldbox/skills/testbox/assertions
๐Ÿ”— https://skills.boxlang.io/skills/raw/coldbox/skills/testbox~assertions

TestBox Assertions โ€” $assert Reference

When to Use This Skill

  • Writing xUnit-style assertions using the $assert object in test functions
  • Using the full testbox.system.Assertion API for validation
  • Registering inline or class-based custom assertions with addAssertions()
  • Using BoxLang dynamic assertXxx() method variants

The $assert Object

Every TestBox bundle receives $assert โ€” an instance of testbox.system.Assertion. It is available in both xUnit test functions and BDD it() blocks.

function testUserCreation() {
    var user = userService.create( { name: "Alice", email: "[email protected]" } )
    $assert.isNotNull( user )
    $assert.isEqual( "Alice", user.name )
    $assert.typeOf( "struct", user )
}

Complete Assertion Reference

Boolean

$assert.isTrue( actual, [message] )
$assert.isFalse( actual, [message] )

Equality

$assert.isEqual( expected, actual, [message] )                // case-insensitive
$assert.isEqualWithCase( expected, actual, [message] )
$assert.isNotEqual( expected, actual, [message] )

Null

$assert.null( actual, [message] )
$assert.notNull( actual, [message] )

Emptiness

$assert.isEmpty( target, [message] )      // array, struct, string, query
$assert.isNotEmpty( target, [message] )

Size / Length

$assert.lengthOf( target, length, [message] )
$assert.notLengthOf( target, length, [message] )

Key Existence (Structs)

$assert.key( target, key, [message] )
$assert.notKey( target, key, [message] )
$assert.deepKey( target, key, [message] )        // recursive search
$assert.notDeepKey( target, key, [message] )

Inclusion (Strings / Arrays)

$assert.includes( target, needle, [message] )              // case-insensitive
$assert.includesWithCase( target, needle, [message] )
$assert.notIncludes( target, needle, [message] )
$assert.notIncludesWithCase( target, needle, [message] )

Type Checks

$assert.typeOf( type, actual, [message] )       // uses isValid() under the hood
$assert.notTypeOf( type, actual, [message] )
$assert.instanceOf( actual, typeName, [message] )
$assert.notInstanceOf( actual, typeName, [message] )

Common type values: array, struct, component, numeric, boolean, date, string, uuid, email, url, query

Numeric Comparisons

$assert.isGT( actual, target, [message] )
$assert.isGTE( actual, target, [message] )
$assert.isLT( actual, target, [message] )
$assert.isLTE( actual, target, [message] )
$assert.between( actual, min, max, [message] )
$assert.closeTo( expected, actual, delta, [datePart], [message] )

String / Regex

$assert.match( actual, regex, [message] )            // case-insensitive
$assert.matchWithCase( actual, regex, [message] )
$assert.notMatch( actual, regex, [message] )

Exceptions

// Assert a closure THROWS
$assert.throws( target, [type], [regex], [message] )

// target must be a closure/function reference
$assert.throws( () => service.delete( 999 ), "NotFoundException" )
$assert.throws( () => service.delete( 999 ), "NotFoundException", "999" )

// Assert a closure DOES NOT throw
$assert.notThrows( target, [type], [regex], [message] )
$assert.notThrows( () => service.safeOperation() )

Force Pass/Fail/Skip

$assert.fail( [message] )             // forcibly fail the test
$assert.skip( message, [detail] )     // skip current test with a message

Generic Expression Assert

$assert.assert( expression, [message] )
// example:
$assert.assert( user.age >= 18, "User must be an adult" )

BoxLang Dynamic Assertion Methods

When running tests in BoxLang, you can call any $assert method as a top-level function by prefixing it with assert:

// Standard $assert style
$assert.isTrue( myBool )
$assert.isEqual( expected, actual )
$assert.between( value, 1, 100 )

// BoxLang dynamic method style (identical behaviour)
assertIsTrue( myBool )
assertIsEqual( expected, actual )
assertBetween( value, 1, 100 )
assertThrows( () => badCall(), "MyException" )
assertCloseTo( 3.14, 3.14159, 0.01 )

Common Assertion Patterns

// Struct shape
$assert.isNotEmpty( responseData )
$assert.key( responseData, "id" )
$assert.key( responseData, "name" )
$assert.typeOf( "numeric", responseData.id )

// Array contents
$assert.typeOf( "array", results )
$assert.isNotEmpty( results )
$assert.lengthOf( results, 3 )
$assert.includes( results, "expectedValue" )

// Exception handling
$assert.throws(
    () => userService.findById( -1 ),
    "ValidationException",
    "-1"
)

// Approximate date equality
$assert.closeTo(
    expected: now(),
    actual:   user.createdAt,
    delta:    2,
    datePart: "s"
)

Custom Assertions

Inline Registration

Register in beforeTests() (xUnit) or beforeAll() (BDD) to keep assertions clean across specs:

function beforeTests() {
    addAssertions( {

        isValidEmail: function( actual ) {
            return isValid( "email", actual )
                ? true
                : fail( "[#actual#] is not a valid email address" )
        },

        isUUID: function( actual ) {
            return isValid( "uuid", actual )
                ? true
                : fail( "[#actual#] is not a UUID" )
        },

        hasNoErrors: function( actual ) {
            return ( actual.keyExists( "errors" ) && !actual.errors.isEmpty() )
                ? fail( "Response has errors: #serializeJSON( actual.errors )#" )
                : true
        }

    } )
}

// Usage
function testEmailValidation() {
    $assert.isValidEmail( "[email protected]" )     // passes
    $assert.isValidEmail( "not-an-email" )           // fails
    $assert.isUUID( createUUID() )
}

Class-Based Assertion Library

For shared, reusable assertions across multiple test bundles:

// tests/helpers/AppAssertions.cfc
component {

    function assertIsActiveUser( expected, actual ) {
        return ( actual.keyExists( "isActive" ) && actual.isActive )
            ? true
            : fail( "User [#actual.name ?: 'unknown'#] is not active" )
    }

    function assertHasPermission( expected, actual ) {
        return ( actual.permissions.findNoCase( expected ) > 0 )
            ? true
            : fail( "User does not have permission [#expected#]" )
    }

    function assertResponseSuccess( expected, actual ) {
        return actual.success
            ? true
            : fail( "Response was not successful. Message: #actual.message ?: ''#" )
    }

}
function beforeTests() {
    // Single class
    addAssertions( "tests.helpers.AppAssertions" )

    // Multiple classes
    addAssertions( "tests.helpers.AppAssertions,tests.helpers.SecurityAssertions" )
    // or array:
    addAssertions( [ "tests.helpers.AppAssertions", "tests.helpers.SecurityAssertions" ] )
}

function testAdminUser() {
    var admin = userService.findById( 1 )
    $assert.isActiveUser( admin )
    $assert.hasPermission( "ADMIN", admin )
}

$assert vs expect() Guide

Use $assert when:

  • Writing xUnit-style test functions
  • You prefer imperative isEqual( a, b ) syntax
  • You need assert( expression ) for arbitrary boolean checks

Use expect() when:

  • Writing BDD specs
  • You want fluent chaining: expect( x ).toBe( y ).toHaveKey( "z" )
  • You want expectAll() for collection assertions
  • You want custom matchers with not negation

Both are available in the same bundle โ€” mix freely.