xUnit.net Extensibility Brad Wilson Jim Newkirk
Schedule Assert Extensibility9:00 Before/After Extensibility9:45 Fact Extensibility10:15 BREAK10:45 Fixture Extensibility11:00 Runner Extensibility11:30 Putting it all Together11:45
Assert Extensibility
Not Easy to Add New Asserts Limitations of the platform & language Provide core assertions with the framework Keep “assert language” consistent No differentiation between failure and exceptions
Customization of Comparisons IEquatable / IEqualityComparer Assert.Contains Assert.Equal IComparable / IComparer Assert.InRange Fallback for Contains & Equal
Asserts that Return Values When type is tested Assert.IsAssignableFrom Assert.IsType Assert.Throws When collections are tested Assert.Single Exception catcher Record.Exception
Example Compare dates without times
Exercise Finish by 9:45
Before/After Extensibility
Design Cross-cutting concerns Reusable attribute Initializing environment Cleaning up after stateful tests Runs regardless of test outcome Has no access to test class or method Unspecified order (compose for guarantee)
Example Rollback database
Brainstorming Exercise Finish by 10:15
Fact Extensibility
Design Answers: “What is a test method?” Enumeration of tests Execution of tests Metadata (skip, timeout, display name)
Why? Metadata changes “I want all my tests to have a timeout” “I want the display name of my test to be something other than method name” Enumeration changes “I want this test method to be run many times, perhaps with different input values for each run” Execution changes “I want to do something different than just running the method with no parameters”
Example [Theory] attribute
Exercise Followed by break, back by 11:00
Fixture Extensibility
IUseFixture Share reusable fixture setup and teardown Constructor Dispose Most frameworks encourage base classes here Lack of multiple inheritance in the CLR “Inherit to be reused, not to reuse”
Example Test data seed & cleanup
ITestClassCommand and RunWith Answers: “What is a test class?” Pre- and post-fixture behavior Pre- and post-test behavior Test class creation & cleanup Test method discovery Test method ordering
Example Remove Randomization
Exercise Finish by 11:30
Runner Extensibility
Design Version resilient runner APIs Link against xunit.runner.utility.dll, not xunit.dll Test assembly lives in a separate app domain Assembly Configuration File (Optional) Shadow Copy
Low-Level API Exector (remote) ExecutorWrapper (local) On the wire, it’s: XML as a string (for status) Boolean continue flag (to cancel) Don’t use this.
High-Performance API Thin wrapper on top of ExecutorWrapper TestRunner TestRunnerResult IRunnerLogger Cracks the XML into simple values Not stateful; callback is mandatory Runners: MSBuild, TD.NET, Resharper
Object-Oriented API Object model on top of ExecutorWrapper MultiAssemblyTestEnvironment TestAssembly, TestClass, TestMethod TestStatus ITestMethodRunnerCallback Cracks the XML into objects Stateful; callback is optional Runners: Console, GUI
Project files (.xunit) One or more assemblies Output types & locations Filters
Example xunit.console
Putting it all Together
Example BDD with [Observation]
Example BDD with SubSpec
Example Amalga Best Practice Analyzer
Exercise
Thank @xunit