22 testcases - ranhs/soda-test GitHub Wiki
Soda-Test also gives a way to write tests in the concept of test-cases and test-step (not only for unit-tests). The Test-Steps are defined as methods in a different class (than the describe class). The test-step methods can except any argument as needed. The test-case are defined as methods in the describe class, in global context on in a specific context. For each test-case you need to define the class where the steps are defined. you can define the steps in the test-case method, and pass them (the test-step methods) any arguments you know about at design time.
To define test-step you need to define a class (no decorator is need for this class). In this Test-Stpes-Class you can define any members that can hold data between steps, and any methods as you want. For a method to be reconised as a test-step (meaning that it can be called from the test-case) you need to add to that method a decorator testStep without any arguments.
class SampleTestStepsTest {
@testStep()
step1(): TR {
expect(1).to.equal(1)
console.log('step1')
}
@testStep()
async step2(name: string): PTR {
expect(2).to.equal(2)
console.log('step2', name)
await sleep(100)
}
}
Note that a test-step method defined in this way, cannot use the done argument, but it can be asynchronic by returning a promise.
In this example, there are 2 steps, step1 and step2. step1 is a synchronic step that has no arguments, and step2 is an asynchronic step that gets one string argument. Note that those steps when decleared don't have there text, as it is with the it decorator.
In current version, you cannot use sinons in steps like those.
A test-case define a senario that uses predfined test-steps, it may call a step more than once, and it may pass different arguments to it in each call. When calling a test-step, the test-case need to define the name (text) of the step to be display when execute.
A test-case method is defined in a class that has a describe decorator. You may mix test-case and and it steps, in the same describe class but it is not recommend to mix them in the same context, since the order of execution is not garenty.
test-case method need to have the testCase decorator. This decorator has 2 mandatory arguments and 1 optional:
- The name (text) of the test-case
- The class where the steps are defined
- Optionaly array of arguments to pass to the test-steps class constructor when creating it for this test-case
The test-case method has a single argumet of the generic type stepMethod with the generic argument of the test-steps-class. This argument is the step method that is used to define a step with sepcific name and then define the step method is should run with the argument it should run with.
@testCase("sample case", SampleTestStepsTest)
case1(step: stepMethod<SampleTestStepsTest>): void {
step("step1").step1()
step("step2").step2("AAA")
step("step2").step2("BBB")
step("step1-finish").step1()
}
In the above example the method case1 is defined as test-step that its name is "sample case" and is using the SampleTestStepsTest class for it steps. This case defines 4 steps. Note that you may use the same name again (regardless of when test-step-method you use). Calling the step method with the step name/text, define the step. The return value of the step method is an object that looks like the test-steps-class, but it is used to define the steps, so you can call one one method each time, and it must be a method that has the testStep decorator. The argument passed to the test-step methods must be known at design time, you cannot get values from the steps and use them in the next step.
The output of the above example is something like this:
sample case
step1
√ step1
step2 AAA
√ step2 (102ms)
step2 BBB
√ step2 (103ms)
step1
√ step1-finish
Assuming you have the following test-steps-class:
class MyTestCase {
constructor(private expectedValue: string) {
}
@testStep()
Validate(value: string): TR {
expect(value).to.equal(this.expectedValue)
}
}
Since this class has argument in its constructor you need to pass it to the test-case method. You do that by giving the testCase decorator a third argument that is an array of all arguments that constractor needs.
@testCase("Sample Case", MyTestCase, ["XXX"])
case2( step: stepMethod<MyTestCase> ): void {
step("sample step").Validate("XXX")
}
In some cases you might want to use differnt instances of the Test-Steps-Class in the same test case. To do this you can pass a second argument to the step method. This optional argument is a number of the index of the instance to use. By default all step execution uses instance #0.
class MyTestCase {
value: string
@testStep()
setValue(value: string) {
this.value = value
}
@testStep()
checkValue(value: string) {
expect (this.value).to.equal(value)
}
}
@testCase("Sample Case", MyTestCase)
case3( step: stepMethod<MyTestCase> ): void {
step("set value1").setValue("value1")
step("set value2 to instance 1", 1).setValue("value2")
step("value 1 is still on instance 0", 0).checkValue("value1")
step("and value 2 is on instnace 1", 1).checkValue("value2")
}