Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WatiN in Visual Studio 2008 - second test method fails

When trying to run a very simple WatiN 2.0 (CTP3) test in Visual Studio 2008 I found that the first one always executes fine. The second test method seem to break something in the IE object producing the following exception:

Test method testProject.WatinTest.testTwo threw exception: System.Runtime.InteropServices.InvalidComObjectException: COM object that has been separated from its underlying RCW cannot be used..

A sample code is below. Due to the way the initialization method is workin in VS2008 the browser variable has to be defined as static which I believe could be a key to the problem. Unfortunately unless the browser is opened in the common method it means a separate window for every test which is not ideal

I would be very grateful for any ideas on how to fix that. Google search and SO search did not produce any useful results so I hope that a good answer to this question will help the community. Many thanks,


    private static IE ie

    [ClassInitialize]
    public static void testInit(TestContext testContext)
    {
        ie = new IE("http://news.bbc.co.uk");
    }

    [TestMethod]
    public void testOne()
    {
        Assert.IsTrue(ie.ContainsText("Low graphics"));
    }

    [TestMethod]
    public void testTwo()
    {
        Assert.IsTrue(ie.ContainsText("Low graphics"));
    }
like image 905
Ilya Kochetov Avatar asked Mar 24 '09 21:03

Ilya Kochetov


2 Answers

I have heard this problem before and meant to investigate this for a while. Now that WatiN 2.0 beta 1 is available I sat down and created a helper class to solve this problem with Visual Studios test runner. Following the helper class and the revamped test class. I also blogged about this solution to give it even more exposure.

public class IEStaticInstanceHelper
{
    private IE _ie;
    private int _ieThread;
    private string _ieHwnd;

    public IE IE
    {
        get
        {
            var currentThreadId = GetCurrentThreadId();
            if (currentThreadId != _ieThread)
            {
                _ie = IE.AttachToIE(Find.By("hwnd", _ieHwnd));
                _ieThread = currentThreadId;
            }
            return _ie;
        }
        set
        {
            _ie = value;
            _ieHwnd = _ie.hWnd.ToString();
            _ieThread = GetCurrentThreadId();
        }
    }

    private int GetCurrentThreadId()
    {
        return Thread.CurrentThread.GetHashCode();
    }
}

And the test class using this helper:

[TestClass]
public class UnitTest 
{
    private static IEStaticInstanceHelper ieStaticInstanceHelper;

    [ClassInitialize]
    public static void testInit(TestContext testContext)
    {
        ieStaticInstanceHelper = new IEStaticInstanceHelper();
        ieStaticInstanceHelper.IE = new IE("http://news.bbc.co.uk");
    }

    public IE IE
    {
        get { return ieStaticInstanceHelper.IE; }
        set { ieStaticInstanceHelper.IE = value; }
    }

    [ClassCleanup]
    public static void MyClassCleanup()
    {
        ieStaticInstanceHelper.IE.Close();
        ieStaticInstanceHelper = null;
    }

    [TestMethod]
    public void testOne()
    {
        Assert.IsTrue(IE.ContainsText("Low graphics"));
    }

    [TestMethod]
    public void testTwo()
    {
        Assert.IsTrue(IE.ContainsText("Low graphics"));
    }
}

HTH, Jeroen

like image 138
Jeroen van Menen Avatar answered Nov 05 '22 07:11

Jeroen van Menen


I was looking for this same thing, and the answer of jvmenen helped me out. However, there has been some updates to WatiN since that answer was given, so I had to rewrite the helper class a bit to be consistent with the latest WatiN version (currently 2.0.20).

WatiN no longer contains the IE.AttachToIE function, so I had to modify that a bit. In addition I also made the helper class using generics, so that any browser type can be used and not only IE (I believe IE and Firefox is supported by WatiN now, and Chrome is to come).

So in case anybody else is looking for this as well, here is my version of the IEStaticInstanceHelper (now called StaticBrowserInstanceHelper):

class StaticBrowserInstanceHelper<T> where T : Browser
{
    private Browser _browser;
    private int _browserThread;
    private string _browserHwnd;

    public Browser Browser
    {
        get
        {
            int currentThreadId = GetCurrentThreadId();
            if (currentThreadId != _browserThread)
            {
                _browser = Browser.AttachTo<T>(Find.By("hwnd", _browserHwnd));
                _browserThread = currentThreadId;
            }
            return _browser;
        }
        set
        {
            _browser = value;
            _browserHwnd = _browser.hWnd.ToString();
            _browserThread = GetCurrentThreadId();
        }
    }

    private int GetCurrentThreadId()
    {
        return Thread.CurrentThread.GetHashCode();
    }
}

Hope this helps somebody :)

like image 25
Julian Avatar answered Nov 05 '22 07:11

Julian