Skip to content

3. Setup and Teardown

Chesko edited this page May 16, 2016 · 9 revisions

To help a test suite DRY up any duplicated setup and teardown code, Lilac provides the beforeEach and afterEach functions. As the name implies, the beforeEach function is called once before each spec in the file in which it is defined, and the afterEach function is called once after each spec.

beforeEach and afterEach are not functions you call, they are functions you override. They are "magic" functions that will be called for you automatically if you define them in your test script.

Here is an example test suite that has duplicate set-up and teardown code:

function TestSuites()
    describe("Story quest", storyQuestSuite())
endFunction

function storyQuestSuite()
    it("should give the player the power sword when the quest starts", powerSwordTest())
    it("should make sure that the NPC alias is filled when the quest starts", aliasCheckTest())
    it("should make sure the stage gets set to 10 after the quest starts", stageCheckTest())
endFunction

function powerSwordTest()
    if MyQuest.IsRunning()
	    MyQuest.Stop()
    endif
	
    MyQuest.Start()
    expectInt(Game.GetPlayer().GetItemCount(PowerSword), to, beGreaterThanOrEqualTo, 1)

    MyQuest.Stop()
    Game.GetPlayer().RemoveItem(PowerSword, 1)
endFunction

function aliasCheckTest()
    if MyQuest.IsRunning()
	    MyQuest.Stop()
    endif
    QuestAlias.Clear()
	
    MyQuest.Start()
    expectRef(QuestAlias.GetActorRef(), notTo, beNone)

    MyQuest.Stop()
    QuestAlias.Clear()
endFunction

function stageCheckTest()
    if MyQuest.IsRunning()
	    MyQuest.Stop()
    endif
    MyQuest.SetStage(0)

    MyQuest.Start()
    expectInt(MyQuest.GetStage(), to, beEqualTo, 10)

    MyQuest.Stop()
    MyQuest.SetStage(0)
endFunction

Here is the same test suite, but written a little differently. We use beforeEach and afterEach to wrap up our set-up code so our specs only contain the parts important to the feature under test.

function TestSuites()
    describe("Story quest", storyQuestSuite())
endFunction

function storyQuestSuite()
    it("should give the player the power sword when the quest starts", powerSwordTest())
    it("should make sure that the NPC alias is filled when the quest starts", aliasCheckTest())
    it("should make sure the stage gets set to 10 after the quest starts", stageCheckTest())
endFunction

function beforeEach()
	if MyQuest.IsRunning()
	    MyQuest.Stop()
    endif
    QuestAlias.Clear()
    MyQuest.SetStage(0)
endFunction

function afterEach()
	MyQuest.Stop()
	QuestAlias.Clear()
	MyQuest.SetStage(0)

	int power_sword_count = Game.GetPlayer().GetItemCount(PowerSword)
	if power_sword_count > 0
		Game.GetPlayer().RemoveItem(PowerSword, power_sword_count)
	endif
endFunction

function powerSwordTest()
    MyQuest.Start()
    expectInt(Game.GetPlayer().GetItemCount(PowerSword), to, beGreaterThanOrEqualTo, 1)
endFunction

function aliasCheckTest()
    MyQuest.Start()
    expectRef(QuestAlias.GetActorRef(), notTo, beNone)    
endFunction

function stageCheckTest()
    MyQuest.Start()
    expectInt(MyQuest.GetStage(), to, beEqualTo, 10)
endFunction

There is also beforeAll and afterAll functions available. Like the names imply, beforeAll will run once before all test cases (and also before any beforeEach functions, if defined) and afterAll runs after all specs have completed (and after the last afterEach function has run).

Limitations

  • Because of the way Lilac is implemented, beforeEach and afterEach are called one extra time after every test case has completed. So, they will be called back to back a final time, with no test case. Make sure that nothing bad happens if they are called without a test in between. If your tests are decoupled from each other adequately, this shouldn't be a problem.
  • You can't have different beforeEach, afterEach, beforeAll, or afterAll behavior depending on which test suite you're in. They apply for every single test case in every suite in a test file. (You can't trick it by using different states for each suite, either.)

If you need suite-specific set-up or tear-down code, write your own functions to do this and call them at the top / bottom of your test cases yourself, like so.

function TestSuites()
    describe("A suite", suiteA())
    describe("Another suite", suiteB())
endFunction

function suiteA()
    it("should do stuff", testDoStuff()
    it("should do other stuff", testDoOtherStuff()
endFunction

function suiteB()
    it("should drive to the store", testDriveToStore()
    it("should do a backflip", testDoABackflip()
endFunction

function beforeEach_suiteA()
    ; Stuff to set up each test in suite A
endFunction

function afterEach_suiteA()
    ; Stuff to tear down each test in suite A
endFunction

function beforeEach_suiteB()
    ; Stuff to set up each test in suite B
endFunction

function afterEach_suiteB()
    ; Stuff to tear down each test in suite B
endFunction


function testDoStuff()
    beforeEach_suiteA()
    ; Test logic
    afterEach_suiteA()
endFunction

function testDoOtherStuff()
    beforeEach_suiteA()
    ; Test logic
    afterEach_suiteA()
endFunction

function testDriveToStore()
    beforeEach_suiteB()
    ; Test logic
    afterEach_suiteB()
endFunction

function testDoABackflip()
    beforeEach_suiteB()
    ; Test logic
    afterEach_suiteB()
endFunction

Clone this wiki locally