In this page
Testing with GreyCat
Testing is essential to ensure that a GreyCat project behaves as expected. This section provides guidance on how to set up and run tests effectively.
GreyCat natively integrates a framework for unit tests.
To run your tests simply execute the following command greycat test
.
Test function naming convention
Function decorated by a @test pragma will be considered as a test unit by GreyCat.
@test
fn my_test_function() {
Assert::isNull(null); // probably valid assertion...
}
Output from running greycat test
project::my_test_function ok (5us)
tests success: 1, failed: 0, skipped: 0
A module (file) can integrate several tests directly within the sources.
Execution order of all tests will follow definition order within one module.
//project.gcl
@test
fn test1() {}
@test
fn test2() {}
Output
project::test1 ok (1us)
project::test2 ok (0us)
tests success: 2, failed: 0, skipped: 0
All the `@test` in a module share the same context. Therefore, any modifications to a module variable in a test will be available to other in the same module
Note: the changes will not effectively be saved to disk, they will be discarded at the end of the module test executionSetup / Teardown
If you are doing any kind of integration test between the database and business logic you would require a setup step to populate the database with data. The following tests would all be valid:
var n: node<int?>;
/// This will be run once prior to any test in the module
fn setup() {
// do some setup..
n.set(1);
}
/// This will be run once after the tests in the module
fn teardown() {
// do some clean up..
}
@test
fn some_test() {
Assert::equals(*n, 1);
n.set(42);
}
@test
fn following_test() {
Assert::equals(*n, 42);
}
project::setup ok (7us)
project::some_test ok (5us)
project::following_test ok (0us)
project::teardown ok (0us)
tests success: 4, failed: 0, skipped: 0
The setup
/teardown
behavior comes in handy for reading sample data and creating indexes or timeseries, or even spawning Docker containers.
Test modules naming convention
If a file ends with _test.gcl suffix It will be excluded from the build when running greycat build
.
A classical project tree would look like this, you are of course free to implement your own structure.
├── project.gcl
├── src
│ ├── api.gcl
│ ├── model.gcl
│ └── model_test.gcl
└── test
└── api_test.gcl
- src directory contains model and api sources and eventually simple unit tests
- test contains every remaining tests sources usually bigger integration tests, that you want to exclude from the final build
GreyCat test command return code
GreyCat test command return 0 in case of success (CI script friendly)
greycat test
echo $?
> 0
and non zero in case of failure
@test
fn fail(){ throw "very bad";}
project::fail failed (428us)
Error: very bad
at fail (project.gcl:98:30)
tests success: 0, failed: 1
echo $?
> 5
Assert type
/// `Assert` is mainly used for testing purposes.
/// It verifies that assertions you make on the state of your data is correct, or throws an `Error`.
type Assert {
/// Verifies that `a` is equal to `b`, throws an error if not. `a` and `b` can be of any type.
static native fn equals(a: any?, b: any?);
/// Verifies that `a` is equal to `b`, throws an error if not. `a` and `b` must be floats.
static native fn equalsd(a: float, b: float, epsilon: float);
/// Verifies that `a` is equal to `b`, throws an error if not. `a` and `b` must be tensors.
static native fn equalst(a: Tensor, b: Tensor, epsilon: float);
/// Verifies that `v` is true, throws an error if not.
static native fn isTrue(v: bool);
/// Verifies that `v` is false, throws an error if not.
static native fn isFalse(v: bool);
/// Verifies that `v` is null, throws an error if not.
static native fn isNull(v: any?);
/// Verifies that `v` is not null, throws an error if not.
static native fn isNotNull(v: any?);
}