Last active
December 21, 2022 12:54
-
-
Save georgejecook/d3daa95ba92f3458100a5a5025cf63b9 to your computer and use it in GitHub Desktop.
write unit tests
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
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" | |
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
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 | |
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
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" |
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
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" |
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
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" |
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
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. |
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
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