DelayedConstraint fails polling properties on references which are initially null
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
NUnit Framework |
Fix Released
|
Medium
|
Charlie Poole | ||
NUnit V2 |
Fix Released
|
Medium
|
Charlie Poole |
Bug Description
Having seen the great progress made on bug #890129, I've been using the After() constraint even more!
(Still using v2.5.10.11092)
I noticed a quirk with how (properties of) objects which are initially null are polled.
An example:
string statusString = null; // object starts off as null
var worker = new BackgroundWorker();
worker.
worker.DoWork += delegate { Thread.
worker.
Assert.That(() => statusString, Has.Length.
The assert will fail after its first poll, reporting:
Parameter name: actual
I assume this is because the 'statusString' object is null, so fetching the 'Length' property causes a ArgumentNullExc
However, I'd expect that the test would at least continue to try to poll even if the value is initially null, in case it gets initialised before the timeout.
A few simple workarounds exist:
Adding a prior null check to the constraint:
Assert.That(() => statusString, Is.Not.
Or adding another separate DelayedConstraint before the Assert which checks for non-null, like this:
Assert.That(() => statusString, Is.Not.
Assert.That(() => statusString, Has.Length.
Perhaps that is because each constraint must pass or timeout before the next is run. The documentation doesn't specify whether each 'After' assert is run on a separate thread or whether earlier ones block.
description: | updated |
Changed in nunitv2: | |
status: | New → Triaged |
importance: | Undecided → Medium |
Changed in nunitv2: | |
assignee: | nobody → Charlie Poole (charlie.poole) |
Changed in nunit-3.0: | |
status: | New → Triaged |
importance: | Undecided → Medium |
assignee: | nobody → Charlie Poole (charlie.poole) |
milestone: | none → 2.9.6 |
Changed in nunit-3.0: | |
status: | Triaged → In Progress |
status: | In Progress → Fix Committed |
Changed in nunitv2: | |
milestone: | none → 2.6.0 |
Changed in nunitv2: | |
status: | Triaged → Fix Committed |
Changed in nunitv2: | |
status: | Fix Committed → Fix Released |
Changed in nunit-3.0: | |
status: | Fix Committed → Fix Released |
Although the 2.6 beta 2 has a fix for use of polling with After, this particular issue hasn't come up before.
Although what you propose makes sense, it's not entirely clear how we can implement it because it's entirely possible to be testing for a null value...
Assert.That(() => statusString, Is.Null. After(3000, 100));
A silly example, but one we have to deal with.
One approach would be for DelayedConstraint to analyze all following constraints to determine if a null reference will cause a problem. This could be messy and violates the independence of composed constraints. Another might be to catch the null reference exception and ignore it during polling.
I think your first workaround is better, since it doesn't depend on knowledge of NUnit's internals. The After constraint is in fact run on a separate thread, but the main thread blocks until it is complete.
Charlie