views:

188

answers:

3

I am attempting to unit test a WCF host management engine that I have written. The engine basically creates ServiceHost instances on the fly based on configuration. This allows us to dynamically reconfigure which services are available without having to bring all of them down and restart them whenever a new service is added or an old one is removed.

I have run into a difficulty in unit testing this host management engine, however, due to the way ServiceHost works. If a ServiceHost has already been created, opened, and not yet closed for a particular endpoint, another ServiceHost for the same endpoint can not be created, resulting in an exception. Because of the fact that modern unit testing platforms parallelize their test execution, I have no effective way to unit test this piece of code.

I have used xUnit.NET, hoping that because of its extensibility, I could find a way to force it to run the tests serially. However, I have not had any luck. I am hoping that someone here on SO has encountered a similar issue and knows how to get unit tests to run serially.

NOTE: ServiceHost is a WCF class, written by Microsoft. I don't have the ability to change it's behavior. Hosting each service endpoint only once is also the proper behavior...however, it is not particularly conducive to unit testing.

+1  A: 

I don't know the details, but it sounds like you might be trying to do integration testing rather than unit testing. If you could isolate the dependency on ServiceHost, that would likely make your testing easier (and faster). So (for instance) you might test the following independently:

  • Configuration reading class
  • ServiceHost factory (possibly as an integrtion test)
  • Engine class that takes an IServiceHostFactory and an IConfiguration

Tools that would help include isolation (mocking) frameworks and (optionally) IoC container frameworks. See:

TrueWill
I'm not trying to do integration testing. I do indeed need to do unit testing. I am thoroughly versed in TDD/BDD terms and practices (IoC, DI, Mocking, etc.), so the run of the mill kind of stuff like creating factories and using interfaces is not what I am in need of (its already done, except in the case of ServiceHost itself.) ServiceHost isn't a dependency that can be isolated, as it isn't properly mockable (as much of the .NET System namespaces.) I really need a way to run the unit tests serially.
jrista
@jrista - no slight on your skills was intended. I'm not a WCF developer, but would it be possible for the engine to return a wrapper around ServiceHost with an interface on the wrapper? Or perhaps a custom factory for ServiceHosts?
TrueWill
The hosting engine does not return any ServiceHosts. It actually does not return anything, it simply manages the creation, opening, and closing of ServiceHosts internally. I could wrap all the fundamental WCF types, but that is a LOT of work that I haven't really been authorized to do. Also, as it turned out, the problem is not caused by parallel execution, and will still happen during normal operation. I started another question here on SO about the problem, and hopefully I'll get an answer.
jrista
@TrueWill: BTW, I wasn't worried about you slighting my skills at all...I just didn't want to get a lot of run-of-the-mill answers that cover all the common stuff about unit testing. I needed a quick answer on a very specific problem. Sorry if I came off a bit gruff, wasn't my intention. I just have pretty limited time to get this thing working.
jrista
@jrista: No problem. Thanks!
TrueWill
+2  A: 

Maybe you can use Advanced Unit Testing. It allows you to define the sequence in which you run the test. So you may have to create a new cs file to host those tests.

Here's how you can bend the test methods to work in the sequence you want.

[Test]
[Sequence(16)]
[Requires("POConstructor")]
[Requires("WorkOrderConstructor")]
public void ClosePO()
{
  po.Close();

  // one charge slip should be added to both work orders

  Assertion.Assert(wo1.ChargeSlipCount==1,
    "First work order: ChargeSlipCount not 1.");
  Assertion.Assert(wo2.ChargeSlipCount==1,
    "Second work order: ChargeSlipCount not 1.");
  ...
}

Do let me know whether it works.

Ngu Soon Hui
Great article. I actually had it bookmarked on CP. Thanks for the link, but as it turned out, the problem seems to be much deeper, as test runners do not seem to run tests in parallel.
jrista
Wait, first you say you don't want the test to run in parallel, and then you say that the problem is that the test runners don't run tests in parallel... so which is which?
Ngu Soon Hui
+1  A: 

See this post

Curious. The tests certainly appear to run in parallel, as when I run each test individually, they all succeed.
jrista
Thanks for the link. Seems that the error is still occurring when the tests are run individually...its just getting hidden by another, less apparent issue.
jrista