Created
December 1, 2013 14:54
-
-
Save adamcameron/7734936 to your computer and use it in GitHub Desktop.
Code for article "Unit Testing / TDD - passing data to on() and trigger()"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// CustomAssertions.cfc | |
component { | |
public void function assertStructKeysCorrect(required string keys, required struct struct, string message){ | |
var assertionArgs = { | |
expected = listSort(keys, "textnocase"), | |
actual = listSort(structKeyList(struct), "textnocase") | |
}; | |
if (structKeyExists(arguments, "message")){ | |
assertionArgs.message = message; | |
} | |
assertEquals(argumentCollection=assertionArgs); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<cfscript> | |
function createEventObject(){ | |
var eventContainer = {}; | |
return { | |
on = function(required string event, required function handler, struct data={}){ | |
if (!structKeyExists(eventContainer, event)){ | |
eventContainer[event] = []; | |
} | |
arrayAppend(eventContainer[event], arguments); | |
}, | |
trigger = function(required string event, struct additionalParameters={}){ | |
if (structKeyExists(eventContainer, event)){ | |
for (eventEntry in eventContainer[event]){ | |
var eventObj = { | |
event = event, | |
data = eventEntry.data | |
}; | |
eventEntry.handler(event=eventObj, argumentCollection=additionalParameters); | |
} | |
} | |
} | |
}; | |
}; | |
</cfscript> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// TestBase.cfc | |
component extends="mxunit.framework.TestCase" { | |
public void function beforeTests(){ | |
addAssertDecorator("CustomAssertions"); | |
include "./function.cfm"; | |
} | |
public void function setup(){ | |
variables.eventObject = createEventObject(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// TestCreateEventObject.cfc | |
component extends="TestBase" { | |
public void function testBaseline(){ | |
createEventObject(); | |
// it doesn't error. That's it | |
} | |
public void function testReturnValues(){ | |
assertIsStruct(variables.eventObject, "Returned value should be a struct"); | |
assertStructKeysCorrect( | |
"on,trigger", | |
variables.eventObject, | |
"Incorrect keys returned in eventObject" | |
); | |
assertTrue( | |
isClosure(variables.eventObject.on), | |
"The returned on() value should be a function" | |
); | |
assertTrue( | |
isClosure(variables.eventObject.trigger), | |
"The returned trigger() value should be a function" | |
); | |
} | |
public void function testOnRequiresEventArg() { | |
var failMsg = "on() should require an EVENT argument"; | |
try { | |
variables.eventObject.on(handler=function(){}); | |
fail(failMsg); | |
} catch (any e){ | |
// can't catch this coherently by exception type as CF and Railo return completely different exceptions here | |
assertTrue( | |
findNoCase("event", e.message) && findNoCase("parameter", e.message), | |
failMsg | |
); | |
} | |
} | |
public void function testOnRequiresHandlerArg() { | |
var failMsg = "on() should require an HANDLER argument"; | |
try { | |
variables.eventObject.on(event="TestEvent"); | |
fail(failMsg); | |
} catch (any e){ | |
assertTrue( | |
findNoCase("handler", e.message) && findNoCase("parameter", e.message), | |
failMsg | |
); | |
} | |
} | |
public void function testTriggerRequiresEventArg() { | |
var failMsg = "trigger() should require an EVENT argument"; | |
try { | |
variables.eventObject.trigger(); | |
fail(failMsg); | |
} catch (any e){ | |
assertTrue( | |
findNoCase("event", e.message) && findNoCase("parameter", e.message), | |
failMsg | |
); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// TestOn.cfc | |
component extends="TestBase" { | |
public void function testOnStoresHandler() { | |
structDelete(variables, "testOnStoresHandlerResponse"); // ensure it doesn't exist | |
var handlerResponse = createUuid(); | |
variables.eventObject.on("TestEvent", function(){ | |
variables.testOnStoresHandlerResponse = handlerResponse; | |
}); | |
variables.eventObject.trigger("TestEvent"); | |
assertTrue( | |
structKeyExists(variables, "testOnStoresHandlerResponse"), | |
"testOnStoresHandlerResponse should have been created" | |
); | |
assertEquals( | |
handlerResponse, | |
variables.testOnStoresHandlerResponse, | |
"testOnStoresHandlerResponse set incorrectly" | |
); | |
} | |
public void function testOnStoresMultipleEvents() { | |
structDelete(variables, "testOnStoresMultipleEvents1"); // ensure it doesn't exist | |
structDelete(variables, "testOnStoresMultipleEvents2"); // ensure it doesn't exist | |
var handlerResponse1 = createUuid(); | |
var handlerResponse2 = createUuid(); | |
variables.eventObject.on("TestEvent1", function(){ | |
variables.testOnStoresMultipleEvents1 = handlerResponse1; | |
}); | |
variables.eventObject.on("TestEvent2", function(){ | |
variables.testOnStoresMultipleEvents2 = handlerResponse2; | |
}); | |
variables.eventObject.trigger("TestEvent1"); | |
assertTrue( | |
structKeyExists(variables, "testOnStoresMultipleEvents1"), | |
"testOnStoresMultipleEvents1 should have been created" | |
); | |
assertEquals( | |
handlerResponse1, | |
variables.testOnStoresMultipleEvents1, | |
"testOnStoresMultipleEvents1 set incorrectly" | |
); | |
variables.eventObject.trigger("TestEvent2"); | |
assertTrue( | |
structKeyExists(variables, "testOnStoresMultipleEvents2"), | |
"testOnStoresMultipleEvents2 should have been created" | |
); | |
assertEquals( | |
handlerResponse2, | |
variables.testOnStoresMultipleEvents2, | |
"testOnStoresMultipleEvents2 set incorrectly" | |
); | |
} | |
public void function testOnStoresMultipleHandlers() { | |
structDelete(variables, "TestOnStoresMultipleHandlers1"); // ensure it doesn't exist | |
structDelete(variables, "TestOnStoresMultipleHandlers2"); // ensure it doesn't exist | |
var handlerResponse1 = createUuid(); | |
var handlerResponse2 = createUuid(); | |
variables.eventObject.on("TestEvent", function(){ | |
variables.testOnStoresMultipleHandlers1 = handlerResponse1; | |
}); | |
variables.eventObject.on("TestEvent", function(){ | |
variables.testOnStoresMultipleHandlers2 = handlerResponse2; | |
}); | |
variables.eventObject.trigger("TestEvent"); | |
assertTrue( | |
structKeyExists(variables, "testOnStoresMultipleHandlers1"), | |
"testOnStoresMultipleHandlers1 should have been created" | |
); | |
assertEquals( | |
handlerResponse1, | |
variables.testOnStoresMultipleHandlers1, | |
"testOnStoresMultipleHandlers1 set incorrectly" | |
); | |
assertTrue( | |
structKeyExists(variables, "testOnStoresMultipleHandlers2"), | |
"testOnStoresMultipleHandlers2 should have been created" | |
); | |
assertEquals( | |
handlerResponse2, | |
variables.testOnStoresMultipleHandlers2, | |
"testOnStoresMultipleHandlers2 set incorrectly" | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// TestTrigger.cfc | |
component extends="TestBase" { | |
// currently trigger() tests are actuaqlly performed as part of the on() tests. | |
public void function beforeTests(){ | |
super.beforeTests(); | |
testOn = new TestOn(); | |
testOn.beforeTests(); | |
} | |
public void function setup(){ | |
super.setup(); | |
testOn.setup(); | |
} | |
// TODO: find a way to decouple these tests | |
public void function testTriggerCalledStoredHandler() { | |
testOn.testOnStoresHandler(); | |
} | |
public void function testTriggerCalledMultipleStoredEvents() { | |
testOn.testOnStoresMultipleEvents(); | |
} | |
public void function testTriggerNonExistentEvent() { | |
variables.eventObject.trigger("EventWithNoHandlers"); | |
// the test is that it doesn't error | |
} | |
public void function testTriggerCalledMultipleStoredHandlers() { | |
testOn.testOnStoresMultipleHandlers(); | |
} | |
public void function testTriggerPassesEventObjToHandler() { | |
variables.eventObject.on("TestEvent", function(){ | |
if (!structKeyExists(arguments, "event")){ | |
throw(type="MissingArgumentException", message="Event object not passed to handler"); | |
} | |
}); | |
try { | |
variables.eventObject.trigger("TestEvent"); | |
} | |
catch (MissingArgumentException e){ | |
fail(e.message); | |
} | |
} | |
public void function testTriggerPassesEventInEventObjToHandler() { | |
variables.eventObject.on("TestEvent", handlerForTestTriggerPassesEventInEventObjToHandler); | |
try { | |
variables.eventObject.trigger("TestEvent"); | |
} | |
catch (MissingEventException e){ | |
fail(e.message); | |
} | |
} | |
public void function testTriggerPassesDefaultDataInEventObjToHandler() { | |
variables.eventObject.on("TestEvent", function(){ | |
if (!structKeyExists(arguments.event, "data")){ | |
throw(type="MissingDataException", message="Data not passed to handler"); | |
} | |
}); | |
try { | |
variables.eventObject.trigger("TestEvent"); | |
} | |
catch (MissingDatatException e){ | |
fail(e.message); | |
} | |
} | |
public void function testTriggerPassesSpecificDataInEventObjToHandler() { | |
var testData = {key="value"}; | |
variables.eventObject.on( | |
"TestEvent", | |
function(){ | |
if (!structKeyExists(arguments.event, "data")){ | |
throw(type="MissingDataException", message="Data not passed to handler"); | |
} | |
if (!structKeyExists(arguments.event.data, "key")){ | |
throw(type="InvalidDataException", message="key not found in data"); | |
} | |
if (arguments.event.data.key != "value"){ | |
throw(type="InvalidDataException", message="key has incorrect value"); | |
} | |
}, | |
testData | |
); | |
try { | |
variables.eventObject.trigger("TestEvent"); | |
} | |
catch (MissingArgumentException e){ | |
fail(e.message); | |
} | |
} | |
public void function testTriggerDefaultsAdditionalParameters() { | |
variables.eventObject.on( | |
"TestEvent", | |
function(){ | |
if (structKeyList(arguments) != "event"){ | |
throw(type="UnexpectedArgumentsException", message="trigger() passed unexpected arguments"); | |
} | |
} | |
); | |
try { | |
variables.eventObject.trigger("TestEvent"); | |
} | |
catch (UnexpectedArgumentsException e){ | |
fail(e.message); | |
} | |
} | |
public void function testTriggerPassesAdditionalParameters() { | |
var additionalParams ={ | |
triggerParam1 = "triggerParam1Value", | |
triggerParam2 = "triggerParam2Value" | |
}; | |
variables.eventObject.on( | |
"TestEvent", | |
function(){ | |
var argNames = structKeyList(arguments); | |
if (listSort(argNames, "textNoCase") != "event,triggerParam1,triggerParam2"){ | |
throw(type="UnexpectedArgumentsException", message="trigger() passed unexpected arguments: #argNames#"); | |
} | |
} | |
); | |
try { | |
variables.eventObject.trigger("TestEvent", additionalParams); | |
} | |
catch (UnexpectedArgumentsException e){ | |
fail(e.message); | |
} | |
} | |
private void function handlerForTestTriggerPassesEventInEventObjToHandler(required struct event){ | |
if (!structKeyExists(arguments.event, "event")){ | |
throw(type="MissingEventException", message="Event name not passed to handler"); | |
} | |
if (arguments.event.event != "TestEvent"){ | |
throw(type="InvalidEventException", message="Event object did not contain correct event name"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment