Bootstrapper class
You configure Specify using a bootstrapper class that provides one convenient place for configuration.
The bootstrapper class lets you configure the following items:
- Html Report: The configuration values for the BDDfy HTML report.
- Logging: A flag to specify whether logging of scenarios is enabled. If so, Specify adds a BDDfy processor to log the results of each scenario using LibLog.
- Application Container: Gets the IoC container that will be used for the lifetime of the application. This is the container that stores all of the scenarios you write and any other services you want to register. This would be the TinyIoc container for Specify, Autofac for the Autofac plugin, or you could write an adapter for a different IoC container. The bootstrapper class has a virtual ConfigureContainer method which you can override to register services in the container. You can also override the BuildApplicationContainer method, but you should only do that if you are using a different IoC container.
- Mocking Framework: Specify will automatically detect if you are using NSubstitute, Moq, or FakeItEasy (in that order). If you want to change which one Specify selects you are able to override the selection.
- PerAppDomainActions: Set actions that will be run before and after all the scenarios (at the beginning/end of AppDomain).
- PerScenarioActions: Set actions that will be run before and after each scenario.
SpecifyBootstrapper.cs File
The SpecifyBootstrapper.cs
file is injected into your test project when you install Specify. (You are free to rename it to anything you like. The important thing is that it inherits from the IBootstrapSpecify
interface). The SpecifyBootstrapper.cs file actually inherits from the DefaultBootstrapper base class which takes care of wiring up the in-built TinyIoc container. You can add items to the TinyIoc container that you want to be available for every test in the ConfigureContainer
method.
/// <summary>
/// The startup class to configure Specify with the default TinyIoc container.
/// Make any changes to the default configuration settings in this file.
/// </summary>
public class SpecifyBootstrapper : DefaultBootstrapper
{
public SpecifyBootstrapper()
{
LoggingEnabled = true;
HtmlReport.ReportHeader = "Specify Examples";
HtmlReport.ReportDescription = "Unit Specifications";
HtmlReport.OutputPath = Path.GetDirectoryName(GetType().GetTypeInfo().Assembly.Location);
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.LiterateConsole()
.WriteTo.RollingFile("log-{Date}.txt")
.CreateLogger();
}
/// <summary>
/// Register any additional items into the TinyIoc container or leave it as it is.
/// </summary>
/// <param name="container">The <see cref="TinyIoCContainer"/> container.</param>
public override void ConfigureContainer(TinyIoCContainer container)
{
}
}
If you use a Specify plugin, then that will have its own bootstrapper class, which you should use. For example, if you use Specify.Autofac, then it will inject a SpecifyAutofacBootstrapper.cs file for you to bootstrap the application with. The difference is that it will wire up the Autofac container and so the ConfigureContainer method will provide an Autofac ContainerBuilder
parameter instead of the TinyIoc container.
/// <summary>
/// Register any additional items into the Autofac container using the ContainerBuilder or leave it as it is.
/// </summary>
/// <param name="builder">The Autofac <see cref="ContainerBuilder"/>.</param>
public override void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule<SubcutaneousTestsAutofacModule>();
}
Html Report
You can configure the report in the bootstrapper constructor using the HtmlReport property.
public class SpecifyBootstrapper : DefaultBootstrapper
{
public SpecifyBootstrapper()
{
HtmlReport.ReportHeader = "Contoso University";
HtmlReport.ReportDescription = "Unit Specifications";
HtmlReport.ReportType = HtmlReportConfiguration.HtmlReportType.Metro;
HtmlReport.OutputFileName = "metro.html";
}
...
}
This extends the BDDfy DefaultHtmlReportConfiguration
class, so you can configure everything on the report that BDDfy lets you configure. In addition, you can set the ReportType
to Classic
or Metro
.
Mocking Framework
Say, for example, that you wanted to use Moq for mocking and that you were also using TestStack's test data library Dossier, which has a dependency on NSubstitute. Specify would attempt to resolve requested services using NSubstitute, by convention, even though your specifications are using the Moq syntax. No worries, simply set the bootstrapper's MockFactory
property to an instance of an object that implements IMockFactory. For example:
MockFactory = new MoqMockFactory();
Specify has three built-in mock factory implementations, for NSubstitute, Moq, and FakeItEasy. If you want to plug in a different mocking framework, just implement this simple interface:
public interface IMockFactory
{
object CreateMock(Type type);
}
Per Application Actions
Represent an action to be performed once per Application (before and after scenarios are run). Just create a class that implements the IPerApplicationAction
interface. (This used to be called IPerAppDomainAction
in earlier iterations of Specify, but with the advent of .Net Core this is less appropriate).
public interface IPerApplicationAction
{
void Before();
void After();
}
For example, if you wanted to rebuild the database before all the tests ran:
public class RebuildDatabaseAction : IPerApplicationAction
{
public void Before()
{
Db.RebuildDatabase();
}
public void After()
{
// do nothing
}
}
And then add an instance of the class in the constructor of the bootstrapper:
PerAppDomainActions.Add(new RestDatabaseAction());
Per Scenario Actions
Similar to the per Application action, but represents an action to be performed before and after each scenario. The PerScenario action has access to the child container that is created for that particular scenario. Just create a class that implements the IPerScenarioActions
interface.
public interface IPerScenarioActions
{
void Before(IContainer container);
void After();
}
For example, if you wanted to reset the database data before each test (using Respawn):
public class ResetDatabaseAction : IPerScenarioActions
{
public void Before(IContainer container)
{
var checkpoint = new Checkpoint
{
SchemasToExclude = new[] { "RoundhousE" },
TablesToIgnore = new[] { "sysdiagrams", "__MigrationHistory" }
};
checkpoint.Reset(Db.ConnectionString);
}
public void After()
{
// do nothing
}
}
Again, you can add an instance of the action in the constructor of the bootstrapper.
PerScenarioActions.Add(new ResetDatabaseAction());