Skip to content

Commit

Permalink
feat: add mock function and test functions (#36)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: adds insertKopytkoUnitTestSuiteArgument bs_const flag
  • Loading branch information
bchelkowski authored Aug 2, 2022
1 parent e52de61 commit bc75923
Show file tree
Hide file tree
Showing 21 changed files with 1,167 additions and 142 deletions.
83 changes: 74 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- [Limitations](#limitations)
- [API](#api)
- [Example test app config and unit tests](#example-test-app-config-and-unit-tests)
- [Migration from v1 to v2](#migration-from-v1-to-v2)

The unit testing framework works on top of the [Roku Unit Testing framework](https://github.com/rokudev/unit-testing-framework). There are some differences between those two frameworks.

Expand All @@ -17,6 +18,7 @@ The unit testing framework works on top of the [Roku Unit Testing framework](htt
We believe tests should be close to the tested objects.

The expected structure of the app:

```
components
_mocks
Expand All @@ -27,7 +29,9 @@ The expected structure of the app:
MyComponent.xml
MyService.brs
```

The `_tests` folders should be placed near to the tested entity. Each test suite gains extra powers:

- no need for xml files
- no need to define test suites functions in an array
- ability to import dependencies
Expand Down Expand Up @@ -69,6 +73,15 @@ Remark: You can use any name for the test environment, just be consistent.
}
```

4. \[Temporary\] To not force [migration from v1 to v2](#migration-from-v1-to-v2) to be imidiate we introduced a bs_const flag (details in Migration part). The flag will be temporary for the depreciation period. In your manifest file please add bs_const:
```js
{
bs_const: {
insertKopytkoUnitTestSuiteArgument: false,
}
}
```

## Running Unit Tests

Simply
Expand Down Expand Up @@ -111,9 +124,9 @@ end function
function MyServiceTestSuite() as Object
ts = KopytkoTestSuite()
ts.setBeforeAll = sub (ts as Object)
beforeAll(sub (_ts as Object)
' do something
end sub
end sub)
return ts
end function
Expand All @@ -124,8 +137,8 @@ function TestSuite__MyService_Main() as Object
ts = MyServiceTestSuite()
ts.name = "MyService - Main"
ts.addTest("it should create new instance of the service", function (ts as Object) as String
return ts.assertNotInvalid(MyService())
it("should create new instance of the service", function (_ts as Object) as String
return expect(MyService()).toBeValid()
end function)
return ts
Expand All @@ -137,7 +150,7 @@ function TestSuite__MyService_getData() as Object
ts = MyServiceTestSuite()
ts.name = "MyService - getData"
ts.addTest("it should return some data", function (ts as Object) as String
it("should return some data", function (_ts as Object) as String
' Given
service = MyService()
expected = { arg: "abc" }
Expand All @@ -146,7 +159,7 @@ function TestSuite__MyService_getData() as Object
result = service.getData("abc")
'Then
return ts.assertEqual(result, expected)
return expect(result).toEqual(expected)
end function)
return ts
Expand Down Expand Up @@ -213,16 +226,52 @@ The service can be used like a regular object:
data = service.getData("/test")
```

When dependency is mocked (`@mock`).
You can use our `mockFunction` to set returned value of the mocked function. For example.

```brs
it("should return mocked function value", function (_ts as Object) as String
' Given
expected = 123
mockFunction("functionName").returnedValue(expected)
' When
result = functionReturningFunctionNameResult()
'Then
return expect(result).toEqual(expected)
end function)
```

Or you can check if mocked function was called properly

```brs
it("should call functionName once with argument a = 1", function (_ts as Object) as String
' When
result = functionReturningFunctionNameResult()
'Then
return [
expect("functionName").toHaveBeenCalledTimes(1),
expect("functionName").toHaveBeenCalledWith({ a: 1 }),
]
end function)
```

[Here](docs/api/KopytkoMockFunction.md) are listed all `mockFunction` methods.

There are also plenty of examples [here](/example/app/components/_tests/mockExamples.test.brs).

Calls to the methods or constructor can be inspected:
```brightscript
?m.__mocks.exampleService.getData.calls[0].params.arg
?m.__mocks.exampleService.constructorCalls[0].params.dependency
? mockFunction("ExampleService.getData").getCalls()[0].params.arg
? mockFunction("ExampleService").getConstructorCalls()[0].params.dependency
```

## Setup and Teardown

Roku Unit Testing Framework provides the way to execute your custom code before/after every test suite.
However, to give more flexibility, Kopytko Unit Testing Framework overwrites `setUp` and `tearDown` properties of a test suite, so you shouldn't use them. Instead, add your function via `setBeforeAll` or `setAfterAll` methods of `KopytkoTestSuite`.
However, to give more flexibility, Kopytko Unit Testing Framework overwrites `setUp` and `tearDown` properties of a test suite, so you shouldn't use them. Instead, add your function via `beforeAll` or `afterAll` methods of `KopytkoTestSuite`.
`KopytkoFrameworkTestSuite` already contains some additional code to prepare and clean a test suite from Kopytko ecosystem related stuff.
Notice that if you have test cases of a unit split into few files, every file creates a separate test suite, therefore all `beforeAll` and `afterAll` callbacks will be executed once per a file.

Expand All @@ -238,7 +287,23 @@ Functions passed into all these methods and arrays should have just one `ts` arg

- [KopytkoTestSuite](docs/api/KopytkoTestSuite.md)
- [KopytkoFrameworkTestSuite](docs/api/KopytkoFrameworkTestSuite.md)
- [KopytkoTestFunctions](docs/api/KopytkoTestFunctions.md)
- [KopytkoExpect](docs/api/KopytkoExpect.md)
- [KopytkoMockFunction](docs/api/KopytkoMockFunction.md)

## Example test app config and unit tests

Go to [/example](example) directory

## Migration from v1 to v2

Version 2 introduces new shorthand functions and because of that, we were able to remove the test suite object argument from the test case function.

Now if you want to get the `ts` (test suite) object, you can get it by calling the `ts()` function in a test case.

In order to not make trouble for projects that already use v1, we introduced a **bs_const** flag [**insertKopytkoUnitTestSuiteArgument**](/example/manifest.js). So if you **don't want to change the current test cases implementation** add it to your manifest with the value **set to true**.

When you want to use our new shorthand methods and you **don't need a test suite object argument**, as you don't use it, **set this flag to false**.

**IMPORTANT: This flag is only temporary and will be removed in the future.
The desired solution is to not use the test suite argument.**
Loading

0 comments on commit bc75923

Please sign in to comment.