Type Resolver for xUnit.net; open source project
21 August 2008 ~ December 2008
  Winter Style | Home » Type Resolver
 
 

Ever since I started unit testing my code, I have been attracted to the light-weight frameworks that offer a lot of power with little overhead. In that sense, xUnit.net is by far the king, thanks to its minimalist syntax and extensiblity. However, switching over from MbUnit I did find one feature lacking: the very convenient UsingImplementations attribute for testing all derived types of an interface or base class. This is what the Type Resolver project provides (and with .NET 2.0 generics support to boot :).

The most common use for the UsingImplementations kind of functionality is for contract testing, ensuring that all types implementing an interface (or deriving from a base class) still fulfill the basic requirements of that interface. Thanks to xUnit’s extensability model, the initial job of functionality of “find all derived types” was quite easy to add. Since xUnit already has support for data-driven tests through its Theory attribute, all I needed to do was create my own “InstanceData” attribute for providing the instances of derived types. The hard part came when implementing the same functionality for types and methods with generic arguments :)

Stepping back for a moment, the general way the resolver function of the library works is this:

  1. You give the resolver a base type to search for.
  2. The resolver then searches through all available assemblies for instantiable types derived from the one it was given, where “instantable” simply means the type:
    • was returned by a factory
    • has a default constructor, or
    • has a constructor that takes only instantiable types
  3. Finally, it returns a list of IInstanceCreator objects that represent each of the creation methods found in the previous step, which you can instantaite by calling CreateInstance.

There is some special handling for enumerations and the like, but otherwise that is all the core library does. At least, that is how it works in the absense of generics :)

If the resolver finds a generic type while searching through the collection of available types, then it must first resolve the type’s arguments before it can determine whether or not it is instantiable. Luckily, this is much the same problem as before, as generic type constraints usually take the form of “A must derive form B” or “A must implement IFoo(there are additional constraints that can be applied, such as “a type must be a class”, or “must be a struct”, or “must have a default constructor”, but these are all immediately available on the type and require no searching). Then again, you can also get much more complex generic constraints, like “A must derive from B, and must implement IFoo<A> and IBar<B,C>”, where A, B, and C are all generic type arguments. Again, this is still just a set of derivation requirements; you just have to be careful about extracting nested arguments form chosen closed types, ensuring consistency between arguments, ensuring all open arguments are assigned, etc, etc . . . (Don’t worry, I won’t bore you with any further details here ;)

All of the other features are layered on top of this core bit of functionality. The InstanceData attribute is given the type of each parameter by xUnit, it gives each type to the resolver, and it returns all combinations of the parameter instances for xUnit to run the test method against. The GenericTheory attribute just resolves the generic arguments on the method it is applied to, returning each found method to xUnit to execute.

Since the project was updated for xUnit 1.1 in December 2008, the project has been pretty stable with no major new features. There have been a handful of small updates and bug fixes since then, as well as updated builds when new xUnit versions are released. Otherwise, the project is feature complete and has become another nice, focused addition to my arsenal .NET unit testing tools, and hopefully to others’ as well :)

 
 
Go back a page |  CodePlex Project | Resume Entry | @ | Copyright © 2008-2011 Paul A Hansen. Some rights reserved.