Question

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.

Was it helpful?

Solution

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...

OTHER TIPS

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top