I'm having a weird issue with Silverlight Unit Test Framework. The very first method executed fails, every time. I have a second test with the exact same code, and it passes. The strange thing about the first time it's called is that it actually waits for the timeout and then executes the repository call (underneath it's an HTTP PUT if you care). Here's the code - the first one fails every time, second one passes every time:
[TestMethod]
public void AuthShouldSucceed()
{
var autoResetEvent = new AutoResetEvent(false);
_authRepository.Authenticate(_username, _password, response =>
{
Assert.IsTrue(response);
autoResetEvent.Set();
});
if (!autoResetEvent.WaitOne(Constants.Timeout))
{
Assert.Fail("Test timed out.");
}
}
[TestMethod]
public void AuthShouldSucceed2()
{
var autoResetEvent = new AutoResetEvent(false);
_authRepository.Authenticate(_username, _password, response =>
{
Assert.IsTrue(response);
autoResetEvent.Set();
});
if (!autoResetEvent.WaitOne(Constants.Timeout))
{
Assert.Fail("Test timed out.");
}
}
Edit: My final solution is a modification of Vladmir's solution:
[TestMethod]
[Asynchronous]
public void AuthShouldSucceed()
{
var complete = false;
var result = false;
_authRepository.Authenticate(_username, _password, response =>
{
complete = true;
result = response;
});
EnqueueConditional(() => complete);
EnqueueCallback(() => Assert.IsTrue(result));
EnqueueTestComplete();
}
If you're using Silverlight Unit Tests Framework try to rewrite your test next way:
[TestMethod]
[Asynchronous]
public void AuthShouldSucceed()
{
var done = false;
var authResult = false;
_authRepository.Authenticate(_username, _password, response =>
{
var done = true;
authResult = response;
});
EnqueueConditional(() => done);
EnqueueCallback(() => Assert.IsTrue(authResult));
EnqueueTestComplete();
}
Your test class should be derived from SilverlightTest class:
[TestClass]
public class MyTests: SilverlightTest
Summarizing all written you should be aware of couple important points in writing Unit Tests for Silverlight.
[Asynchronous]
Attribute of test method shows that you are testing part which includes async operations and want to syncronize them for testing purposes. Asynchrony itself in Silverlight Unit Tests Framework is a bit distorted. All "Enqueue" directives are like "postpone this until something happens" which is not a sense which the traditional programming asynchrony meaning has.
EnqueueConditional
Otherwords means wait until condition will be met. And this is one of the most important parts of async tests. After condition becomes legal all
EnqueueCallbacks
until the next EnqueueConditional
will be executed.
EnqueueConditional
repeatedly calls the predicate passed to it on a timer/background thread, checking each time to see if it returns true.
That's why you should avoid using heavy, complex logic within conditions.
EnqueueCallback
Defers code execution until
EnqueueConditional
that precedes it will met condition. It enqueues an Actoin
or an array of Actions
.
EnqueueDelay
Enqueues minimum number of milliseconds/time delay before continuing.
EnqueueTestComplete
Enqueues an action to call
TestComplete
which signals that a test is complete when using Async testing.
Important Note(from documentation):
If you use your own methods for completing, such as an HtmlTimer or other threading method, it is possible that this call will occur AFTER the test has timed out when using Timeouts. As such, be very careful as you could complete the call to the next test.
You can use the Asynchronous keyword in the TestMethod
[TestMethod]
[Asynchronous]
[Description("This test checks when NULL is passed")]
public void Testing()
{
bool done = false;
EnvViewModel test = new EnvViewModel ();
.
.
test.AsyncCallBackCompleted += (() => done = true);
EnqueueCallback(() => test.DataCommand.Execute(null));
EnqueueConditional(() => done);
EnqueueCallback(() => Assert.IsTrue(test.AADTDecisionModelList.Count == 0,
"The result does not have any data."));
EnqueueTestComplete();
}
And make a delegate in the ViewModel to be used to every method that is being tested...
public delegate void AsynCallComplete();
public event AsynCallComplete AsyncCallBackCompleted;
public void InformCallbackCompleted()
{
if (AsyncCallBackCompleted != null)
{
AsyncCallBackCompleted();
}
}
来源:https://stackoverflow.com/questions/11513422/silverlight-async-unit-testing