/expect

Behavior-driven development and test component

Primary Language4DMIT LicenseMIT

expect

language language-top code-size release license discord

Behavior-driven development and test component inspired by RSpec or Jest

Usage

Initialize instance

At the beginning of test method

_ = spec // return a spec instance

Test description

You describe your test and the context using _.describe, and finally do your test using _.it

While (_.describe("A new Scanner"))
	While (_.describe("for an empty string"))
		While (_.it("is at the end"))
			_.scanner:=cs.Scanner.new("")
			_.expect(_.scanner.eos()).to(_.beTrue()) // or ASSERT(_.scanner.eos();_.message())
		End while 
	End while 
	...

If the test failed, the context message will be : "A new Scanner for an empty string is at the end"

Before and after hooks

You can share some initialization code using beforeEach and do some cleaning using afterEach

	...
	While (_.describe("for a non-empty string"))
		
		_.beforeEach(Formula(This.scanner:=cs.Scanner.new("a b c")))
		
		While (_.describe("scan"))
			
			While (_.describe("when the RegExp matches the entire string"))
				While (_.it("returns the entire string"))
					_.expect(_.scanner.scan("a b c")).to(_.beEqualTo(_.scanner.string))
					_.expect(_.scanner.eos()).to(_.beTrue())
				End while 
			End while 
						
			While (_.describe("when the RegExp matches at index 0"))
				While (_.it("returns the portion of the string that matched"))
					_.expect(_.scanner.scan("a")).to(_.beEqualTo("a"))
					_.expect(_.scanner.pos).to(_.beEqualTo(1))
				End while 
			End while 

		End while // end scan
	End while // for a non-empty for a non-empty
End while // A new Scanner

Full example

Matchers

Matchers are heavily inspired by RSpec built-in-matchers

_.expect(<value>).to(_.<predicate>)

or to inverse the predicate

_.expect(<value>).notTo(_.<predicate>)
_.expect(<value>).toNot(_.<predicate>)

with:

  • value: result of your computations to check
  • predicate: a defined predicate such as equal, contain, etc...

Equality

Check if an element is equal

_.expect(1+1).to(_.beEqualTo(2))

String

Check if a string contain an other string

_.expect("seahorse").to(_.contain("sea"))
_.expect("seahorse").to(_.beginWith("sea"))
_.expect("seahorse").to(_.endWith("horse"))

Collections

Check if collection contain an element

_.expect(New collection("Atlantic";"Pacific";"Mississippi")).to(_.contain("Mississippi"))
_.expect(New collection("Atlantic";"Pacific")).toNot(_.contain("Mississippi"))

or check if all elements match an other matcher

_.expect(New collection(1;2;3;4)).to(_.allPass(_.beLessThan(5)))

or use a formula to check if one element match it

_.expect(New collection("Atlantic";"Pacific")).to(_.containElementSatisfying(Formula(Position("A";This.value)=1)))

Nullity

Check if null or not

_.expect(Null).to(_.beNull())
_.expect("Null").notTo(_.beNull())

Emptiness

Check if string, object or collection are empty

_.expect("").to(_.beEmpty())
_.expect("test").toNot(_.beEmpty())
_.expect(New collection("a")).toNot(_.beEmpty())
_.expect(New object()).to(_.beEmpty())

Length

Check the string or collection length

_.expect("test").to(_.haveLength(4))
_.expect(New collection("a")).toNot(_.haveLength(1))

True or False or contain True or False element

Check if True or False

_.expect(True).to(_.beTrue())
_.expect(False).to(_.beFalse())

or if any collection or object contain True or False element

_.expect(True).to(_.beTruthy())
_.expect(New object("message";"Test";"success";True)).to(_.beTruthy())
_.expect(New collection("Test";True)).to(_.beTruthy())

_.expect(False).to(_.beFalsy())
_.expect(New object("message";"Test";"success";False)).to(_.beFalsy())
_.expect(New collection("Test";False;5)).to(_.beFalsy())

Numeric comparison

Compare your numeric result with other numerics

_.expect(1).to(_.beLessThan(2))
_.expect(1).to(_.beLessThanOrEqualTo(2))
_.expect(1).to(_.beLessThanOrEqualTo(1))
_.expect(3).to(_.beGreaterThan(2))
_.expect(3).to(_.beGreaterThanOrEqualTo(2))
_.expect(3).to(_.beGreaterThanOrEqualTo(3))
_.expect(3).notTo(_.beGreaterThanOrEqualTo(4))
_.expect(1.2).to(_.beCloseTo(1.1;0.1))

Error

Wrap using a formula, then check if an assert has been raised. You can match also message or error code

_.expect(Formula(ASSERT(False;"Raise"))).to(_.raiseError())
_.expect(Formula(ASSERT(False;"Raise"))).to(_.raiseError("Assert failed: Raise"))
_.expect(Formula(ASSERT(False;"Raise"))).to(_.raiseError(-10518))
_.expect(Formula(ASSERT(False;"Raise"))).toNot(_.raiseError("Assert failed: Not same message"))
_.expect(Formula(Application version)).toNot(_.raiseError())
_.expect(Formula(Application version())).to(_.raiseError())
_.expect(Formula(Application version())).to(_.raiseError(59))
_.expect(Formula(Application version())).toNot(_.raiseError(100))

Class

Check if your object is an instance of specific class

_.expect($anInstance)).to(_.beAnInstanceOf(cs.MyClass))

Measure / Time

Want to execute a block of code multiple times and measure the time?

$m:=_.measure(5)

While ($m.next())
  // here your block fo code
End while

then you could get the average duration

$m.durationAverage()

or all durations as collection

$m.durations()

You could check the min or max or compute the variance to warn if there is too much difference between each execution

Delay timer

Some times you need to initialize some stuff and do not want to take into account in the measure. You could delay the timer and launch the measure yourself by setting automaticallyStartMeasuring to False and use start and stop functions.

$m:=_.measure(10)
$m.automaticallyStartMeasuring:=False
While ($m.hasNext())
	
     // do init stuff here

	$m.start()
	// code to measure time
	$m.stop()
	
	$m.next()
End while 

TODO

  • Custom errors collect (in _spec.verify Formula) to write to files or asserts
  • ...

Hey, What did you expect?