In this page
Testing with GreyCat
GreyCat test command
Like any other softwares, GreyCat based project need to be test
GreyCat natively integrates a framework for
- unit tests
- integration tests
- api tests
tests can be executed through the test command of GreyCat CLI
greycat test
model_test
customer_validate_creation_time: ok (11 us)
customer_validate_connection_time: ok (1 us)
api_test
prepare: ok (10 us)
api_validate_customer_retrieve: ok (2 us)
tests success: 4, failed: 0
Test modules naming convention
every GreyCat tests should be named with a _test.gcl suffix
a classical project tree view will look like this
├── project.gcl
├── src
│ ├── api.gcl
│ ├── model.gcl
│ └── model_test.gcl
└── test
└── api_test.gcl
- src directory contains model and api sources and eventually unit tests
- test contains every remaining tests sources (integration and api tests usually)
- project root is defined by project.gcl at the root of the project repository and contains @include directives
@include("src");
@include("test");
Test function naming convention
every 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...
}
every Greycat module can integrate several tests directly within the sources
//customer_test.gcl
@test
fn test1(){
}
@test
fn test2(){
}
execution order of all tests will follow definition order within one module
Unit tests
- model.gcl
type Customer {
name: String;
creation_time: time;
last_connection_time: time?;
static fn new(name: String): Customer{
return Customer {name: name, creation_time: time::now()};
}
}
var customers: nodeIndex<String,Customer>?;
- model_test.gcl
use model;
use util;
@test
fn customer_validate_creation_time(){
var c = Customer::new("John Doe");
Assert::equals(c.creation_time.to(DurationUnit::seconds),time::now().to(DurationUnit::seconds));
}
@test
fn customer_validate_connection_time(){
var c = Customer::new("John Doe");
Assert::isNull(c.last_connection_time);
}
API tests (same for integration tests)
- api.gcl
use model;
@expose
fn customer(name: String) : Customer? {
return customers?.get(name);
}
- api_test.gcl
use model;
use api; // this statement makes all API accessible as functions
use util;
@test
fn prepare(){ // must be first in module, prepare all data for api testing
customers ?= nodeIndex<String,Customer>::new();
var c = Customer::new("John Doe");
customers.set(c.name, c);
}
@test
fn api_validate_customer_retrieve(){
var c = customer("John Doe");
Assert::equals(c.name, "John Doe");
}
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";}
greycat test
model_test
customer_validate_creation_time: ok (15 us)
customer_validate_connection_time: ok (1 us)
api_test
prepare: ok (9 us)
api_validate_customer_retrieve: ok (2 us)
fail: {"_type":"core.Error","code":{"_type":"core.ErrorCode","field":"throw"},"value":"very bad","stack":["fail (./test/api_test.gcl:20:22)"]}
tests success: 4, failed: 1
echo $?
> 41
Test vs build
GreyCat automatically remove all tests and associated symbols from final build program
there the following command
greycat build
will produce a project.gcp file
├── project.gcl
├── project.gcp
but the next command
cat project.gcp | grep api_validate
will print nothing, even string literals are dropped by GreyCat build for safety reasons
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](../core/#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?);
// Verifies that `v` is not null, throws an error if not.")
//static native fn fail(f: function);
}