Skip to content
This repository has been archived by the owner on Jul 9, 2022. It is now read-only.

Setups & Cleanups

Matthias Koch edited this page Jun 15, 2016 · 16 revisions

SpecK offers various levels to specify setup and cleanup code:

Since setups and cleanups represent a unit, SpecK guarantees meaningful execution of them in case of exceptions. A typical setup scenario could look like this:

  • Bootstrap.Setup
    • SuiteSetup1.Setup
    • SuiteSetup2.Setup
      • CaseSetup.Setup
      • <Tests>
      • CaseSetup.Cleanup
    • SuiteSetup2.Cleanup
    • SuiteSetup1.Cleanup
  • DatabaseBootstrap.Cleanup

Since Setup1 and Setup2 are on the same level, they will be executed in nested order. If Setup2 throws an exception for some reason, the execution will immediately continue with the execution of the cleanup of Setup1; so the cleanup of Setup2 is skipped.

Lazy AssemblySetup

By inheriting from IAssemblySetup you can create setup/cleanup logic that is executed once for all test suites in an assembly that require the setup:

public class DatabaseAssemblySetup : IAssemblySetup
{
  DbContext Context;

  public void Setup () { /* create connection */ }
  public void Cleanup () { /* close connection */ }
}

public class MySpec : Spec
{
  [AssemblySetup] DatabaseAssemblySetup DatabaseAssemblySetup;
}

Because the outcome of assembly setups is crucial, SpecK injects them into test suites. Note that assembly setups are only executed if they are imported by at least one test suite. It is advisable to create a base class, if many test suites depend on the same bootstrap.

Suite Setup

On suite-level you can use SetupOnce to execute the code only once for all test cases:

public class MySpec : Spec
{
  MySpec()
  {
    SetupOnce (setup: CreateDatabase, cleanup: DropDatabase);
    SetupOnce (setup: CreateTables, cleanup: DropTables);
  }
}

The execution is defined as CreateDatabase, CreateTables, <Tests>, DropTables, DropDatabase

Global Case Setup

With Setup you can declare setup and cleanup code that is execute for each case:

public class MySpec : Spec<DomainType>
{
  MySpec()
  {
    Setup (SetupSubjectInstance, CleanupSubjectInstance);
  }

  void SetupSubject(ITestContext<DomainType> context) { }
  void CleanupSubject(ITestContext<DomainType> context) { }
}

In this case, the execution will be SetupSubject, <Test1>, CleanupSubject, then SetupSubject, <Test2>, CleanupSubject and so on.

Note that if you use the automated subject creation facilities, you will be able to access the subject instance from within the setup and cleanup methods.

Local Case Setup

For individual setups and cleanups, you can use the various GivenUsing overloads:

public class MySpec : Spec
{
  MySpec()
  {
    Specify (x => Foo.Bar())
        .DefaultCase (_ => _
             .GivenUsing (new CultureContext ("en-US"))
             .Given ("custom arrangement", x => { })
             .GivenUsing (setup: SetupStuff, cleanup: CleanupStuff))
             .It ("assertion", x => { }));
  }

  public class CultureContext : IDisposable
  {
    public CultureContext (string culture) { /* save old and set new culture */ }
    public void Dispose() { /* restore old culture */ }
  }
}

As mentioned before, the execution engine will skip cleanups if their related setups were not successful. Usage can also be extended into much cleaner calls like GivenUsingCulture ("en-US").