Thanks for the quick response - much appreciated.
The Inject(_fixture) trick works nicely.
Now, onto the rest.
Background, not important, will provide salient bits here (having said that, the code is clean, interesting and less that 1000 lines and Hanselman says we should read it :D)... SubSpec is an xUnit extension that started as a desire by Phil Haack and was
implemented by Brad Wilson as an xunit sample. A colleague, Johannes Rudolph has forked the sample to add some more capabilities, see https://bitbucket.org/johannesrudolph/subspec/wiki/Home
There is a SpecificationBaseStyle variant of SubSpec which works like idiomatic xunit - porting/generalising AutoFixture.xunit to it would be easy.
Regarding your contention that it relies on anything static, not really. The Specification method when run stashes a set of lambdas for Given When and multiple Then portions. SubSpec then, a la [Theory] runs a separate Given and When pair for each Then and
the test names are based on the strings logged with the lambdas.
So, how does this affect what one'd need to match AutoFixture.xUnit and/or xUnit's normal IUseFixture support?
Firstly, we lose using blocks within the body of the Specification - you're generating 3 lambdas which can share state via the closure but can't e.g. do try/finally or using between blocks
Secondly, if you have multiple things to Dispose, you can normally IUseFixture them separately (or use an aggregate item that manages a set)
So, if your Sut needs disposal, the normal ways - using blocks or IUseFixture are not available
The other case is where one needs to Do something in the When bit which requires cleanup *after* the Then/Assert bit. This doesnt happen often, and normally in a Fact you'd either just use a using (which would include the When bit) or maintain a RX System.CompositeDisposable
or a List<IDisposable> and have that torn down at the end (but it needs to be reliable). The other normal means of managing all this is to stash stuff in the Test Class instance and have it's Dispose do the cleanup.
The other thing that the lambdas make difficult is to share state between the G/W/T blocks - you need to declare them outside the lambdas, default initialize them to avoid the uninitialized variable warnings and then they get captured in a closure
So, why would you want to even use a framework like that?
1) it (by coincidence, but the effect is desirable) optimises for the SUT case - there's a friction to sharing state between the G/W/T phases
2) it lets you put English language spec level descriptions of intent without_underscores_that_are_ugly or CrazyPascalCasing without having to take the hit of something heavier like specflow and its extra assemblies, generated code etc. (esp if you dont
have a magic BA that's going to write or read the Gherkin with you)
3) it's just xunit.net with <1000 lines added
With the above in mind, what falls out is that:
- we want a single SUT
- if the SUT needs access to 5 fixtures, it should be able to get them easily
- the SUT *and the fixtures* may need disposal
The final piece is that right now, AutoFixute.xunit allows me to do
void Test(Sut sut, [Frozen] Fixture1 fixture1, [Frozen] Fixture2 fixture2)
But I cant use it -- so I'm thinking that having the Sut be a SpecContext which
public SutContext(Sut sut, [Frozen] Fixture1 fixture1, [Frozen] Fixture2 fixture2)
_fixture1 = fixture1;
... But there's no way to say
And have the ctor args be .Freeze<T> rather than CreateAnonymous<T> on a case by case basis.
using(var fixture = new DisposingFixture()) // Fixture with a disposer hooked in
var context = fixture.CreateAnonymous<SutContext>()
I could easily use the AutoFixture.xunit stuff as inspiration to achieve it, but am wondering whether there's something more built in. If I looked at the tests I'm sure I'll figure out how to write such a 5 line customization - was just looking to be lazy!
In closing, the niceness of AutoFixture.xunit and all this noise is all but pushing me back to using raw XUnit or considering the SpecificationBaseStyle SubSpec. Or StoryQ...
Thanks for the food for thought and hope you can provide some insights ideas without it stealing too much of your time -- it's nice to get better test reviews for free than are offered over wtwitter by paying something small like $100 per half hour :P