Sherlock
Sherlock

Reputation: 1030

How to Unit test BackgroundWorker C#

I'm trying to unit test, using VS unit testing facility following method.

void Get(string name, Action<string> callBack);

here is unit tester

    [TestMethod]
    public void Test()
    {
        Action<string> cb = name =>
        {
            Assert.IsNotNull(name);
        };

        var d = new MyClass();
        d.Get("test", cb);
    }

The only problem is that internal implementation uses BackgroundWorker, hence callback is invoked on another thread. Here is internal implementation.

    public void Get(string name, Action<string> callBack)
    {
        callBackString = callBack;
        GetData(name);
    }  

    private void GetData(string name)
    {
        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += bw_DoWork;
        bw.RunWorkerCompleted += bw_RunWorkerCompleted;
        bw.RunWorkerAsync(name);
    }

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        //do work here
        if (null != callBackString)
            callBackString("ok");
    }

Of course because Get() returns right away, test completes with success and testing stops, thus RunWorkerCompleted never gets to be executed. I can easily test this via normal application (WPF) because it stays running, yet I'd like to have ability to unit test this.

Any ideas? Thanks in advance.

Upvotes: 9

Views: 8589

Answers (3)

TrueWill
TrueWill

Reputation: 25543

I've written similar code and made it testable by following the IAsyncResult design pattern. My unit tests run against the synchronous (blocking) version of the method. The asynchronous methods can be a single line each, so I didn't write unit tests against those.

Upvotes: 0

Michael Lloyd Lee mlk
Michael Lloyd Lee mlk

Reputation: 14661

I don't know the details for C# & BackgroundWorker but I'd do this by injecting the BackgroundWorker implementation and during the test use a stubbed BackgroundWorker that you can control when it executions and in which thread. If communication between two threads is required then have the stubbed BackgroundWorker create a new thread and have the test pause until it is complete, if not force it to run after the call to get.

Upvotes: 4

Martin Harris
Martin Harris

Reputation: 28617

Something like:

[TestMethod]
public void Test()
{   
    bool running = true;
    string result = null;

    Action<string> cb = name =>
    {
        result = name;
        running = false;
    };

    var d = new MyClass();
    d.Get("test", cb);

    while(running)
    {
        Thread.Sleep(100);
    }

    Assert.IsNotNull(result);
}

Though you probably want to add something in there to stop the test from running forever if it fails...

Upvotes: 8

Related Questions