test-dsl is a test-helper library to write your own DSLs for testing
test-dsl allows you define a set of verbs and conditions, to more easily
concentrate on authoring tests.
Instead of copy-pasting boilerplate and creating hard-to-read tests, this crate allows you to distill the behaviour of your library or application into small actions called 'verbs'.
An example test for an imaginary "http client" crate could look like this:
testcase {
create_mock_server "example.com"
create_client "sut"
connect client="sut" server="example.com"
assert {
check_last_connection status=200
verify_cache client="sut" url="example.com"
}
}
How to use it
Using test-dsl is straightforward:
- You define a test harness
- You define a set of 'verbs' that will allow you to act on your test harness
- You define a set of 'conditions' that you will be able to assert during your tests
For example, a fairly simple test-setup to check arithmetic can be defined as follows:
use Arc;
use FunctionCondition;
use FunctionVerb;
use NamedSource;
let mut ts = new;
ts.add_condition;
ts.add_condition;
ts.add_verb;
ts.add_verb;
let testcases = ts
.parse_testcase
.unwrap;
// Check that its true
testcases.run.unwrap;
testcases.run.unwrap;
Builtin verbs
The following verbs come builtin:
-
repeat <number> { .. }: it allows for repetition of a given block. Used as such:testcase { repeat 3 { print "Hello World" print "World Hello" } } -
group { .. }: it allows to group verbs together. Used as such:testcase { group { print "Hello" print "World" } }NB: There is currently not much use to groups, but this may change in the future
-
assert { .. }: it allows to assert a list of conditions. Used as such:testcase { send_message assert { message_was_sent } }
How the different types relate to eachother
- The main type is
TestDslwhich serves as the coordinator. Ideally you should have a single function creating this object that you can reuse. EachTestDslis generic over your test Harness. Which is basically the 'coordinator' of your test. Think of it like an all-seeing part of your system, that can kick-start functionalities you'd want to test. It's usually best if your harness only interacts with the to-be-tested types through their public functions. But depending on how you organize your code it might also be able to access the inner workings. - The work-horses 🐴 of this crate are the
Verbimplementations. You can implement it yourself, or you can useFunctionVerbfor quick in-line verb definitions.FunctionVerbaccepts closures which take your harness as well as arguments for your verb. - Closely behind are the
Conditions. They allow for verifying your invariants. Similarly to verbs, you can implement the trait yourself, or use theFunctionConditionhelper. ParseArgumentsis the bridge betweenkdlandtest_dsl. It allows verbs and conditions to accept input in form of arguments and child nodes, and put it into a form that the verbs/conditions can then make use of.VerbInstance&ConditionInstanceare both fully-parsed and ready to run verbs & conditions. They are created fromTestDslinstances. Mainly used inParseArgumentsimplementations.