Return to Snippet

Revision: 16658
at December 4, 2009 10:56 by pckujawa


Updated Code
using Empire;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Threading;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;

namespace snippets
{
    [TestClass()]
    public class EmpireApiTest
    {
        private static AutoResetEvent m_testTrigger;
        private object m_testData;
        private int m_timeout = 1000 * 60 * 1; // 1 minute

        static EmpireApiTest()
        {
            Trace.Listeners.Add(new ConsoleTraceListener(false)); // For ReSharper unit test output
            EmpireApi.Initialize(IP, PORT);
            EmpireApi.ErrorRcvd += EmpireApi_ErrorRcvd;
        }

        static void EmpireApi_ErrorRcvd(object sender, EventArgs<string> e)
        {
            Trace.TraceError(e.ToString());
            m_testTrigger.Set();
            //Assert.Fail(e.ToString());
        }

        void Receive(object sender, EventArgs e)
        {
            m_testData = e;
            m_testTrigger.Set();
        }

        public void AsyncTest(Action method, string test)
        {
            method();
            m_testTrigger = new AutoResetEvent(false);
            bool didReturn = m_testTrigger.WaitOne(m_timeout);
            if (!didReturn)
            {
                Assert.Fail(test);
            }
            Trace.WriteLine(String.Format("{0}:
{1}",
                test,
                m_testData));
        }

        [TestMethod()]
        public void ReadVersionTest()
        {
            AsyncTest(
                () =>
                {
                    EmpireApi.ReadVersion_Rcvd += Receive;
                    EmpireApi.ReadVersion();
                },
                "ReadVersionTest"
                );
        }

        [TestMethod()]
        public void ReadVersionTestComplete()
        {
            EmpireApi.ReadVersion_Rcvd += Receive;
            EmpireApi.ReadVersion();
            m_testTrigger = new AutoResetEvent(false);
            bool didReturn = m_testTrigger.WaitOne(m_timeout);
            if (!didReturn)
            {
                Assert.Fail("ReadVersionTest");
            }
            Trace.WriteLine(String.Format("{0}:
{1}",
                "ReadVersionTest",
                m_testData));
        }
    }
}

Revision: 16657
at August 11, 2009 10:55 by pckujawa


Initial Code
using Empire;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Threading;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;

namespace snippets
{
    [TestClass()]
    public class EmpireApiTest
    {
        private static AutoResetEvent m_testTrigger;
        private object m_testData;
        private int m_timeout = 1000 * 60 * 1; // 1 minute

        static EmpireApiTest()
        {
            Trace.Listeners.Add(new ConsoleTraceListener(false)); // For ReSharper unit test output
            EmpireApi.Initialize(IP, PORT);
            EmpireApi.ErrorRcvd += EmpireApi_ErrorRcvd;
        }

        static void EmpireApi_ErrorRcvd(object sender, EventArgs<string> e)
        {
            Trace.TraceError(e.ToString());
            m_testTrigger.Set();
            //Assert.Fail(e.ToString());
        }

        void Receive(object sender, EventArgs e)
        {
            m_testData = e;
            m_testTrigger.Set();
        }

        public void AsyncTest(Action method, string test)
        {
            method();
            m_testTrigger = new AutoResetEvent(false);
            bool didReturn = m_testTrigger.WaitOne(m_timeout);
            if (!didReturn)
            {
                Assert.Fail(test);
            }
            Trace.WriteLine(String.Format("{0}:
{1}",
                test,
                m_testData));
        }

        [TestMethod()]
        public void ReadVersionTest()
        {
            AsyncTest(
                () =>
                {
                    EmpireApi.ReadVersion_Rcvd += Receive;
                    EmpireApi.ReadVersion();
                },
                "ReadVersionTest"
                );
        }

        [TestMethod()]
        public void ReadVersionTestComplete()
        {
            EmpireApi.ReadVersion_Rcvd += Receive;
            EmpireApi.ReadVersion();
            m_testTrigger = new AutoResetEvent(false);
            bool didReturn = m_testTrigger.WaitOne(m_timeout);
            if (!didReturn)
            {
                Assert.Fail("ReadVersionTest");
            }
            Trace.WriteLine(String.Format("{0}:
{1}",
                "ReadVersionTest",
                m_testData));
        }
    }
}

Initial URL
http://jasondotnet.spaces.live.com/blog/cns!BD40DBF53845E64F!170.entry

Initial Description
Since an asynchronous method is usually one you call and then it invokes a callback when it is finished, it is not obvious how to test such a method in a definite manner. In the method described at the above URL, the author uses .NET's System.Threading.AutoResetEvent, along with a member variable, to notify the primary thread that the test method has finished. The source below (from Radiant::Mirage::Empire) tests a method called ReadVersion from an API which fires events at the completion of each command or a special event if there is an error. The static constructor initializes the API, subscribes to the Error event, and adds Trace output to the Console. The two event listeners simply log data (to Trace or to a member variable) and then set the AutoResetEvent so that the calling method can proceed. AsyncTest is a method that allows me to call a method and then perform the same, standard procedures afterwards (creating the AutoResetEvent, waiting for the thread to return, and outputting to Trace). The actual test method, ReadVersionTest, calls AsyncTest with a lambda (which is an anonymous method that gets called inside AsyncTest) that subscribes to the relevant event and issues the specified command. The ReadVersionTestComplete method shows what the code would look like without using the AsyncTest method and lambda.

Initial Title
Testing asynchronous methods in .NET (or, how to make an async method synchronous)

Initial Tags
Net

Initial Language
C#