質問

I am stumped ... This is a follow up post to my previous question on using lambda delegates with Reflection, to perform unit tests on Windows Forms

I got it to work quite nicely and now can use this to confirm certain NFRs.

var monitor = new SemaphoreSlim(1);
monitor.Wait();
var form = new SomeForm();
form.SetControlProperty<TextBox>("tbFirstName", "Text", firstName);
form.SetControlProperty<TextBox>("tbLastName", "Text", lastName);
form.ObserveControlEvents<DataGridView>("dataGridView1", "DataSourceChanged",
    (sender, args) =>
    {
        Trace.WriteLine("Occured in delegate");
        monitor.Release();
    });
Trace.WriteLine("Executing");
var sw = form.ClickButton("btnSearch");
monitor.Wait();
sw.Stop();

However, if I decorate my search and DataGridView.DataSource update methods, with [BackgroundMethod] and [DispatchedMethod], the tests succeed, but no data is actually inserted in the form under test. In other words, tests complete in 0ms, with 0 records in the DataGridView.

I am using PostSharp 2.1.7.35 and 2.1.1.12 PostSharp Threading Toolkit.

What could be the reason for this behavior?

I've tried the path of creating a UnitTest build configuration and using SkipPostSharp compilation symbol, but it did not feel natural to use and had some other issues.

UPDATE

If I use the Task Factory approach, and perform my UI update on a delegate, it works just fine.

UPDATE 2

It also works if I use BackgroundWorker.

UPDATE 3

Actually, BackgroundWorker did not correctly fire an event on task completion.

So what does PostSharp weave in to brake Unit Tests?

役に立ちましたか?

解決

Using this article advice, I have been able to successfully use PostSharp's [BackgroundMethod] and SafeInvoke extension from the CodeProject article. Since it has a couple of typos, here is a re-write:

    public static TResult SafeInvoke<T,TResult>(this T isi, Func<T,TResult> call) where T : ISynchronizeInvoke
    {
        if (isi.InvokeRequired) { 
            IAsyncResult result = isi.BeginInvoke(call, new object[] { isi }); 
            object endResult = isi.EndInvoke(result); return (TResult)endResult; 
        }
        else
            return call(isi);
    }

    public static void SafeInvoke<T>(this T isi, Action<T> call) where T : ISynchronizeInvoke
    {
        if (isi.InvokeRequired) isi.BeginInvoke(call, new object[] { isi });
        else
            call(isi);
    }

I hope it saves someone some time.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top