Skip to content

Instantly share code, notes, and snippets.

@georgejecook
Last active December 21, 2022 12:54
Show Gist options
  • Save georgejecook/d3daa95ba92f3458100a5a5025cf63b9 to your computer and use it in GitHub Desktop.
Save georgejecook/d3daa95ba92f3458100a5a5025cf63b9 to your computer and use it in GitHub Desktop.
write unit tests
I make roku apps in Brighterscript. Brighterscript is an extension of the BrightScript language. It adds classes with the class, end class key words, and provides public, protected and private method visibility. It also adds the "@." expression, which transpiles to ".callFunc", so `node@.sayHello(name)`, transpiles to `node.callFunc("sayHello", name)`
please respond with : "ok"
please respond with : "ok"
This is the api for the test framework I build in Brighterscript. All these functions are on m, for each BaseTestSuite subclass, being tested.
note: the expectCalled methods, taken an invocation as an argument. the thing being invoked _does not_ have to exist, or even have all the properties under test: it creates them automatically. It automatically assets the parameters are as expected.
function setup()
function tearDown()
function beforeEach()
function afterEach()
function fail(msg = "Error" as string) as dynamic
function assertFalse(expr as dynamic, msg = "Expression evaluates to true") as dynamic
function assertTrue(expr, msg = "Expression evaluates to false")
function assertEqual(first, second, msg = "") as dynamic
function assertLike(first, second, msg = "") as dynamic
function assertNotEqual(first, second, msg = "") as dynamic
function assertInvalid(value, msg = "") as dynamic
function assertNotInvalid(value, msg = "") as dynamic
function assertAAHasKey(array, key, msg = "") as dynamic
function assertAANotHasKey(array, key, msg = "") as dynamic
function assertAAHasKeys(array, keys, msg = "") as dynamic
function assertAANotHasKeys(array, keys, msg = "") as dynamic
function assertArrayContains(array, value, key = invalid, msg = "") as dynamic
function assertArrayContainsAAs(array, values, msg = "") as dynamic
function assertArrayNotContains(array, value, key = invalid, msg = "") as dynamic
function assertArrayContainsSubset(array, subset, msg = "") as dynamic
function assertArrayNotContainsSubset(array, subset, msg = "") as dynamic
function assertArrayCount(array, count, msg = "") as dynamic
function assertArrayNotCount(array, count, msg = "") as dynamic
function assertEmpty(item, msg = "") as dynamic
function assertNotEmpty(item, msg = "") as dynamic
function assertArrayContainsOnlyValuesOfType(array, typeStr, msg = "") as dynamic
function assertType(value, typeStr, msg = "") as dynamic
function assertSubType(value, typeStr, msg = "") as dynamic
function assertClass(value, func, msg = "") as dynamic
function assertNodeCount(node, count, msg = "") as dynamic
function assertNodeNotCount(node, count, msg = "") as dynamic
function assertNodeEmpty(node, msg = "") as dynamic
function assertNodeNotEmpty(node, msg = "") as dynamic
function assertNodeContains(node, value, msg = "") as dynamic
function assertNodeContainsOnly(node, value, msg = "") as dynamic
function assertNodeNotContains(node, value, msg = "") as dynamic
function assertNodeContainsFields(node, subset, ignoredFields = invalid, msg = "") as dynamic
function assertNodeNotContainsFields(node, subset, msg = "") as dynamic
function assertAAContainsSubset(array, subset, ignoredFields = invalid, msg = "") as dynamic
function stub(target, methodName, returnValue = invalid, allowNonExistingMethods = false) as object
function expectLastCallToThrowError(error as dynamic)
function expectCalled(invocation as dynamic, returnValue = invalid as dynamic) as object
function stubCall(invocation as dynamic, returnValue = invalid as dynamic) as object
function expectNotCalled(invocation as dynamic) as object
The test framework is @annotation based. It has one describe block, each with multiple @it tests. Each test is named `_`.
The thing being tested, is usually on m, like m.screen, or m.view, or m.manager., whereas m in the test refers to the BaseTestSuite subclass
Here is a sample test.
--------------------------
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@describe("updateHeader")
'+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@it("does not crash if the dateModule is invalid")
function _()
m.expectCalled(m.screen.list.content@.getChild(0), invalid)
m.expectNotCalled(m.screen.updateDateModule(invalid))
m.expectNotCalled(m.screen.list.content@.notifyUpdate())
m.expectNotCalled(m.screen.list@.synchronizeContent())
m.screen.updateHeader()
end function
and here is a sample test that uses parameters
-------------------------------------------------
@it("re-executes the lists's cell onCellDidGainFocus callback, to trigger a new preview timer")
@params(1, 2)
@params(1, 1)
@params(2, 3)
function _(rowIndex, cellIndex)
m.screen.previewSelection = invalid
m.screen.list.focusedRowIndex = rowIndex
m.screen.list.focusedCellIndex = cellIndex
m.expectNotCalled(m.screen.executeSelection)
m.expectCalled(m.screen.resetPreview(true))
m.expectCalled(m.screen.onCellDidGainFocus(rowIndex, cellIndex, 1))
m.screen.continuePreviewIfRequired()
end function
please respond with : "ok"
brighterscript also supports namespaced functions. these can not be stubbed, or mocked with expectCalled, expectNotCalled. most of these namespaced functions will start with "nba." or "mc."; but basically any dotted invocation that is not either on m, or a variable in scope
please respond with : "ok"
in the tests we write, m refers to the test. the thing being tested is usually m.maanager. We don't have to write stub funcions, or even create stub objects. the m.expectCalled, and m.expectNotCalled, methods create, all of the necessary code for us, and automatically assert the correct params and number of invocations.
please respond with : "ok"
couple more points:
- don't forget the members on m, inside the resetState function, are on m.list, in our unit test. Also, please be sure to assert that wasFocused and m.top.visible got changed
- when we create stub objects, like content, in the previous case, we just do this: {id: "content"}
also, we can do @params to pass in params for things like wasFocused, expectedFocus, for example.
close; you're still not getting the expectCalled syntax. it should have been. m.expectCalled(m.list.setState("none")). also I'm not a fan of comments. please don't include them.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment