2

I have always got around this problem by - unfortunately - using events less. However this time I came up with a nifty trick, however I don't think the following would be considered a proper approach. Is there a recommended method to achieve the same results?

NB Without the while you get a null reference exception on the _args.Fixture unless you breakpoint on it - race condition.

private Parser _parser;
private ParsedArgs _args;        

[TestFixtureSetUp]
public void Setup()
{
    _parser = new Parser();
    _parser.DataParsed += DataParsed;
}

void DataParsed(object sender, ParsedArgs e)
{
    _args = e;
}

[Test]
public void TestDocParse()
{
    _parser.ParseFixture(File.ReadAllText(EventDataPath));

    while (_args == null || _args.Fixture == null) { }

    Assert.IsNotNull(_args.Fixture);
    var fixture = _args.Fixture;
    Assert.AreEqual("2F7PY1662477", fixture.Id);            
}

I found that the following led to having to think up a potentially inaccurate timescale for the parsing to have completed...

I am aiming to test that the fixture.Id is equal to "2F7PY1662477".

Thanks

Community
  • 1
  • 1
Matt Canty
  • 2,395
  • 5
  • 35
  • 50
  • 3
    I would use `System.Threading.SpinWait.SpinUntil(() => _args != null && _args.Fixture != null, 30000);` for one, just to make sure that your test never gets stuck in a loop. You could also use an auto reset event, or something like that. – vcsjones Jul 10 '12 at 17:30
  • 1
    There's a couple of things here. One is, of course, you're "spinning" waiting for the parser to complete. and two, this is not only testing the parser, but also testing the eventings. The Test is a bit pointless because you'll never complete the while loop and test that _args.Fixture is not null. – Peter Ritchie Jul 10 '12 at 18:04
  • Nah it does work... I'm just aware of getting stuck in a loop. You raise the further issue that I am in fact testing two parts too. – Matt Canty Jul 11 '12 at 09:00

2 Answers2

2

I would first decouple the test/fixture from requiring some sort of file to read. I would just send in canned data to ParseFixture--you're either testing that you can parse a file or you're testing whether the expected event is raised.

I would then avoid parsing in the background. This will illuminate the race condition because you'll do everything synchronously.

I would then have a flag that signals whether a valid event occurred.

For example:

private bool eventOccurred;
private void DataParsed(object sender, ParsedArgs e)
{
   eventOccurred = e.Id == "2F7PY1662477";
}

[Test]
public void TestDocParse()
{
    _parser.ParseFixture(TextToParse);
    Assert.IsTrue(eventOccurred);
}
Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98
  • This still isn't working. I have moved the parsing into [TestFixtureSetup] just to move it out. I like SpinWait the best so far, because it allows simple addition of a timeout. – Matt Canty Jul 11 '12 at 09:20
  • But the point is you want to simply test the events, not the fact that something is occurring in the background. If you avoid parsing in the background then you don't need the spin wait or the while. – Peter Ritchie Jul 11 '12 at 16:11
  • Ah sorry, maybe I have not been clear. I want to test that the Fixture Id has been correctly parsed as "2F7PY1662477". – Matt Canty Jul 12 '12 at 10:14
  • Right, that was done in the DataParsed method. In there you don't need any sort of test for whether the event was raised (like checking "args" and "args.Fixture) because you're handling the event. We can then validate the event is correct by testing Id there and merge all that into a single bool and assert on that. – Peter Ritchie Jul 12 '12 at 14:05
0
System.Threading.SpinWait.SpinUntil
    (() => _args != null && _args.Fixture != null, 30000);

This makes sure that the parser has completed its job, however it won't leave my tests running if there has been an issue somewhere.

Thanks vcsjones

Matt Canty
  • 2,395
  • 5
  • 35
  • 50
  • So how can I test that Id == "2F7PY1662477" whilst keeping the parse method return void? – Matt Canty Jul 13 '12 at 11:27
  • 1
    My example shows how to do this. The event handler (DataParse) handles the event, when it handles the event it validates that the Id is the expected value, this validates that the event occurred correctly (stored as the eventOccured field in the test class). The test method then asserts that eventOccured is true. This assumes that ParseFixture is synchronous and the event is raised before returning from ParseFixture. This is important in tests; asynchrony in tests makes it very difficult to test accurately. – Peter Ritchie Jul 13 '12 at 15:16