2009-03-24 4 views
8

При попытке запустить очень простой тест WatiN 2.0 (CTP3) в Visual Studio 2008 я обнаружил, что первый всегда выполняется отлично. Второй метод тестирования, кажется, сломать что-то в объекте IE производит следующее исключение:WatiN в Visual Studio 2008 - второй метод тестирования не работает

Метод испытания testProject.WatinTest.testTwo бросил исключение: System.Runtime.InteropServices.InvalidComObjectException: COM объекта, который был разделенных от лежащих в его основе RCW не может быть использован ..

пример кода ниже. Из-за того, как метод инициализации работает в VS2008, переменная браузера должна быть определена как static, которая, я считаю, может быть ключом к проблеме. К сожалению, если браузер не открыт в обычном методе, это означает отдельное окно для каждого теста, который не является идеальным.

Я был бы очень признателен за любые идеи о том, как исправить это. Поиск в Google и поиск SO не дали полезных результатов, поэтому я надеюсь, что хороший ответ на этот вопрос поможет сообществу. Большое спасибо,


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")); 
    } 

ответ

10

Я уже слышал эту проблему и хотел бы изучить это некоторое время. Теперь, когда доступна WatiN 2.0 beta 1, я сел и создал вспомогательный класс для решения этой проблемы с помощью тестировщика Visual Studios. После класса помощника и обновленного тестового класса. Я также blogged об этом решении, чтобы дать ему еще большую экспозицию.

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(); 
    } 
} 

А класс тест с помощью этого помощника:

[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")); 
    } 
} 

НТН, Йерун

+0

Блестящий, Jeroen. Это отличный ответ, и я очень надеюсь, что это поможет многим людям, которые имеют такую ​​же проблему. Кроме того, я надеюсь, что теперь между вашим блогом и SO Google будет в состоянии дать содержательные предложения, когда люди будут искать решения. –

+0

Мне пришлось использовать код Nailuj (на основе вашего кода) для последней версии WatiN. Тем не менее, я получал исключения в ClassCleanup и не мог заставить браузер распоряжаться, не убивая процесс с Process.Kill() ... который является уродливым решением :( –

0

Я думаю, что это связано с тем, как вы держите держание переменной IE. Я использовал его без проблем, как в примере: http://watin.sourceforge.net/. Я рассматриваю тесты ватина как более функциональные/интеграционные тесты, чем модульные тесты, поэтому каждый тест больше похож на историю с различными взаимодействиями. Я использую шаблон объекта страницы, чтобы помочь структурировать код - см. http://code.google.com/p/webdriver/wiki/PageObjects.

Ps. Я рассмотрел повторное использование экземпляра, но на самом деле не пробовал его. Открывающие/закрывающие экземпляры браузера добавляют время на тесты.

+0

Спасибо. Примеры на странице WatiN работают отлично для меня, но для реальных сценариев я хотел бы что-то еще. Мы могли бы использовать шаблон объекта страницы, но его здесь можно было бы сделать код примера нечитаемым. Еще раз спасибо –

+0

Конечно, WatiN на самом деле не касается модульного тестирования, а интеграции/функциональности, но только потому, что вы запускаете тестовый бегун, это не значит, что это должен быть единичный тест. Если вы пишете функциональные/интеграционные тесты, основанные на инфраструктуре единичного тестирования, вы получаете бегун, отчетность, интеграцию с VS, например, с модульным тестом, что является большим усилением, особенно если вы хотите запустить его на сервере CI, где ваш тест выполняется каждый раз, когда новый развертывание приложения. – yoosiba

8

Я искал для этого одно и то же, и ответ jvmenen помог мне. Тем не менее, с тех пор, как был дан ответ, некоторые обновления были обновлены, поэтому мне пришлось переписать вспомогательный класс немного, чтобы соответствовать последней версии WatiN (в настоящее время 2.0.20).

WatiN больше не содержит функцию IE.AttachToIE, поэтому мне пришлось немного изменить ее. Кроме того, я также использовал класс-помощник с использованием дженериков, чтобы можно было использовать любой тип браузера, а не только IE (я считаю, что IE и Firefox теперь поддерживаются WatiN, а Chrome - в будущем).

Таким образом, в случае кто-либо другой ищут для этого, как хорошо, вот моя версия IEStaticInstanceHelper (теперь называется 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(); 
    } 
} 

Надеется, что это помогает кто-то :)