Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I ensure that I dispose of an object in my singleton before the application closes?

I'm using WatiN for some automated tests and what I found was that creating an IE instance for every test was not scalable. The creation and shutdown time of each IE instance was eating me alive:

    [TestMethod]
    public void Verify_Some_Useful_Thing()
    {
        using (var browser = new IE())
        {
            browser.GoTo("/someurl");
            // etc..
            // some assert() statements
        }
     }

However, the using statement did prove useful in that I can always ensure that my IE instance would have its dispose() method called which would close the IE window.

Anyway, I created a singleton which maintained a single IE instance which all my tests use across all my test classes:

public class BrowserPool
{      
    private static readonly Lazy<BrowserPool> _instance = new Lazy<BrowserPool>(() => new BrowserPool());        

    private IE _browser;
    private string _ieHwnd;
    private int _threadId;

    public IE Browser
    {
        get
        {
            var currentThreadId = GetCurrentThreadId();
            if (currentThreadId != _threadId)
            {
                _browser = IE.AttachTo<IE>(Find.By("hwnd", _ieHwnd));
                _threadId = currentThreadId;
            }
            return _browser;
        }
        set
        {
            _browser = value;
            _ieHwnd = _browser.hWnd.ToString();
            _threadId = GetCurrentThreadId();
        }
    }

    /// <summary>
    /// private to prevent direct instantiation.
    /// </summary>
    private BrowserPool()
    {
        Browser = new IE();
    }

    /// <summary>
    /// Get the current executing thread's id.
    /// </summary>
    /// <returns>Thread Id.</returns>
    private int GetCurrentThreadId()
    {
        return Thread.CurrentThread.GetHashCode();
    }

    /// <summary>
    /// Accessor for instance
    /// </summary>
    public static BrowserPool Instance
    {
        get
        {
            return _instance;
        }
    }
}

And the test now:

  [TestMethod]
  public void Verify_Some_Useful_Thing()
  {
        var browser = BrowserPool.Instance.Browser;
        browser.GoTo("/someurl");
        // some assertions
  }

This works well and my tests run much faster now that I'm not opening and closing IE every test. However, I have this one problem in that when the tests complete my IE instance will still remain open.

I can't figure out an elegant way to ensure that BrowserPool.Browser has dispose() or close() called on it before the application ends. I even tried using a finalizer in the BrowserPool class but that didn't seem to work because the _browser variable had already been reclaimed when my finalizer is called.

How can I ensure that dispose() is called on my IE instance after the test run?

like image 640
KingNestor Avatar asked Oct 10 '22 01:10

KingNestor


1 Answers

Use the [AssemblyCleanupAttribute()] to clean resources after your tests found in the assembly are finished.

Btw, never rely on the use of destructors in .NET.

like image 195
Tim Cools Avatar answered Oct 13 '22 11:10

Tim Cools