Blog

Spec Data Binding in TestBox

Luis Majano May 06, 2016

Spread the word

Luis Majano

May 06, 2016

Spread the word


Share your thoughts

This issue has comed up several times in our mailing lists, so why not expand a little with a blog post.

The Problem

Many developers working with TestBox love the BDD approach to spec design. Once they get familiar with the syntax they start getting funky! It is just natural! Since they are coding within a CFC they decide to create dynamic it() or specs by iterating over some type of data collection (queries,arrays,structs). The first iteration of the code might look like this:


// Complex Example
for( var filePath in files ){

    it("#getFileFromPath(filePath)# should be valid JSON", function() {
        
        var json = fileRead(filePath);
        var isItJson = isJSON(json);
        expect(json).notToBeEmpty();
        expect(isItJson).toBeTrue();
        
        if (isItJson) {
            var data = deserializeJSON(json);
            if (getFileFromPath(filePath) != "index.json") {
                expect(data).toHaveKey("name");
                expect(data).toHaveKey("type");
            }
        }

    });
    
}

The Expectation

Now, you would really expect this to work, and it partially does. What you will see is that only the last binding of the iteration works. This is due to the fact that you are iterating and creating closures at runtime. The problem is that closures rely on its environment when executed, not when defined. So in reality, once TestBox executes these closures for evaluation purposes, the last filePath is the one used, since that is the contents of the variable at the time of the execution of the closure, NOT the definition of the closure.

I know, I know, this is really hurting your brain. That's ok. You are getting funky, doesn't mean it is always easy. Anyways, thankfully, TestBox provides a workaround so you can actually bind the spec with runtime definitions so your closures can actually take the right data.

The Solution

The solutions is to use spec data binding in TestBox. Each closure that defines the it() spec, accepts a data argument which is a structure.


it( title="", data={}, body=function( data ){} );

This is passed by TestBox automatically for you. All you have to do is bind it. You do this by passing another argument to the it() spec called data. This now allows you to update your code to the following:


// Complex Example. Let's iterate over a bunch of files and create dynamic specs
for( var filePath in files ){

  it( 
    title="#getFileFromPath( filePath )# should be valid JSON", 
    // pass in a struct of data to the spec for later evaluation
    data = { filePath = filePath },
    // the spec closure accepts the data for later evaluation
    function( data ) {
      var json = fileRead( data.filePath );
      var isItJson = isJSON( json );

      expect( json ).notToBeEmpty();
      expect( isItJson ).toBeTrue();

      if( isItJson ){
          var jsonData = deserializeJSON(json);
          if( getFileFromPath( filePath ) != "index.json"){
              expect( jsonData ).toHaveKey( "name" );
              expect( jsonData ).toHaveKey( "type" );
          }
      }

  });
  
}

Now you can generate dynamic specs and bind them accordingly at runtime! Enjoy!

Add Your Comment

Recent Entries

MatchBox and WebAssembly: Running BoxLang in the Browser and at the Edge

MatchBox and WebAssembly: Running BoxLang in the Browser and at the Edge

The MatchBox open beta is live at https://boxlang.ortusbooks.com/boxlang-framework/matchbox, and it brings something genuinely new to the BoxLang ecosystem: a path into WebAssembly.

That means BoxLang code can now move into browser applications, static-site deployments, edge runtimes, and WASI-style containers - without requiring a JVM. The feature is still beta, but the core direction is already useful: write BoxLang, compile it with MatchBox, and ship the generated WASM artifact to wherever a small portable runtime makes sense.

Jacob Beers
Jacob Beers
June 04, 2026
BoxLang 1.14.0 : BoxSet is Here: BoxLang's New First-Class Set Type

BoxLang 1.14.0 : BoxSet is Here: BoxLang's New First-Class Set Type

BoxLang 1.14.0 ships something that JVM developers have wanted for a long time: a true first-class Set type baked directly into the language. Not a wrapper you reach for manually, not a createObject( "java", "java.util.HashSet" ) incantation you paste from a Stack Overflow answer years ago. A real BoxSet with literal syntax, operator overloads, a full functional pipeline, change listeners, JSON serialization, and deep Java interop.

Luis Majano
Luis Majano
June 03, 2026
BoxLang 1.14.0 : Sets, Ranges, Inner Classes, and a Runtime That Talks Back

BoxLang 1.14.0 : Sets, Ranges, Inner Classes, and a Runtime That Talks Back

BoxLang has never stood still, but 1.14.0 is something different. This is the release where the language stops filling gaps and starts defining what a modern dynamic JVM language looks like on its own terms. Sixty-five issues closed. Four innovative language features. A formatter that has grown up. And a companion module - bx-mcp - that fundamentally changes how you operate a running BoxLang application with AI.

Luis Majano
Luis Majano
June 03, 2026