The first preview release of SpecsFor 3.0 is now available on NuGet. This release cleans up and simplifies much of the core while dropping some ill-conceived features, but it also adds a brand new system for composing test context.
[more]
To try out the new releases, install the prerelease version from NuGet:
PM> Install-Package SpecsFor -Pre
Be warned that there are several breaking changes in this preview release. Here is (I think) a full list:
- ITestState renamed to ISpecs.
- Attribute-based method of specifying context completely removed.
- Given<TContext> and Given(TContext) methods now execute immediately when called. You no longer have to remember to call base.Given().
- AfterEachSpec renamed to AfterSpec to alleviate some confusion about when it is executed.
If you find something else that doesn’t work after upgrade, please let me know. I hate breaking changes, but I feel like these changes are necessary to help SpecsFor grow. Overall, the spec lifecycle is a little cleaner and simpler now with fewer “gotchas” waiting in the wings (such as registering context with Given<TContext> but then forgetting to call base.Given to trigger its execution).
There are lots of enhancements in this release, the biggest of which is what I’m calling “Composable Context.” Composable Context allows you to do things like this:
[SetUpFixture] public class ComposingContextConfig : SpecsForConfiguration { public ComposingContextConfig() { WhenTesting<ILikeMagic>().EnrichWith<ProvideMagicByInterface>(); WhenTesting<SpecsFor<Widget>>().EnrichWith<ProvideMagicByConcreteType>(); WhenTesting(t => t.Name.Contains("running_tests_decorated")).EnrichWith<ProvideMagicByTypeName>(); WhenTesting(t => t.Name.Contains("junk that does not exist")).EnrichWith<DoNotProvideMagic>(); WhenTestingAnything().EnrichWith<ProvideMagicForEveryone>(); WhenTestingAnything().EnrichWith<MyTestLogger>(); } }
Note: full code is available on the Github repo.
These conventions are applied only to tests located within the same namespace as the configuration class or within one of its child namespaces. Composable Context stacks up, too, meaning you can have multiple layers of conventions.
What is Composable Context good for? One possible use is database integration testing:
[SetUpFixture] public class DatabaseConfig : SpecsForConfiguration { public ComposingContextConfig() { WhenTestingAnything().EnrichWith<TransactionScopeWrapper>(); WhenTesting<IRequireDatabase>().EnrichWith<DatabaseFactoryContext>(); } }
With this approach, all specs are automatically wrapped in a TransactionScope, while tests that need access to a database need only implement an interface.
Feedback Is Welcome
I would love to hear what others think. I bounced back and forth for quite a while before settling on the changes in this version, and there are many pieces that I’m still not 100% sold on. This is a preview release. This is not the official 3.0 release. If I nuked your favorite feature, please let me know. If there’s something the Composable Context system won’t let you do, describe it, and I’ll see if it can be added.