2009-03-24 6 views
8

Al intentar ejecutar una prueba WatiN 2.0 (CTP3) muy simple en Visual Studio 2008 encontré que la primera siempre se ejecuta correctamente. El segundo método de prueba parece romper algo en el objeto IE producir la siguiente excepción:WatiN en Visual Studio 2008 - falla el segundo método de prueba

Método de ensayo testProject.WatinTest.testTwo arrojó excepción: System.Runtime.InteropServices.InvalidComObjectException: objeto COM que ha sido separados de su RCW subyacente no se puede utilizarse ..

Un código de ejemplo está por debajo. Debido a la forma en que funciona el método de inicialización en VS2008, la variable del navegador debe definirse como static, lo que creo que podría ser la clave del problema. Lamentablemente, a menos que el navegador se abra en el método común, significa una ventana separada para cada prueba que no es ideal

Estaría muy agradecido por cualquier idea sobre cómo solucionarlo. La búsqueda de Google y la búsqueda SO no arrojaron ningún resultado útil, por lo que espero que una buena respuesta a esta pregunta ayude a la comunidad. Muchas gracias,


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

Respuesta

10

He escuchado este problema antes y tengo la intención de investigar esto por un tiempo. Ahora que WatiN 2.0 beta 1 está disponible, me senté y creé una clase de ayuda para resolver este problema con el test runner de Visual Studios. Siguiendo la clase de ayuda y la clase de prueba renovada. También blogged acerca de esta solución para darle aún más exposición.

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

Y la clase de prueba usando este 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

+0

Brilliant, Jeroen. Esa es una gran respuesta y realmente espero que ayude a muchas personas que tienen el mismo problema. También espero que ahora entre su blog y SO Google pueda dar sugerencias significativas cuando las personas busquen soluciones –

+0

Tuve que usar el código de Nailuj (basado en su código) para obtener la última versión de WatiN. Sin embargo, estaba obteniendo excepciones en ClassCleanup y no puedo conseguir que el navegador elimine sin matar el proceso con Process.Kill() ... que es una solución fea :( –

0

creo que está relacionado con la forma en que está manteniendo una bodega a la variable de IE. Lo he estado usando sin problemas como en la muestra: http://watin.sourceforge.net/. Veo las pruebas de watin como más pruebas funcionales/de integración que las pruebas unitarias, por lo que cada prueba es más como una historia con diferentes interacciones. Uso el patrón de Objeto de página para ayudar a estructurar el código: consulte http://code.google.com/p/webdriver/wiki/PageObjects.

Ps. He considerado reutilizar la instancia pero realmente no lo he intentado. Las instancias de apertura/cierre del navegador agregan tiempo a las pruebas.

+0

Gracias. Los ejemplos en la página WatiN están funcionando bien para mí, pero para los escenarios en vivo me gustaría algo más. Podríamos usar el patrón de Objeto de Página pero ponerlo aquí haría ilegible el código de muestra. Gracias de nuevo –

+0

Por supuesto, WatiN no se trata realmente de pruebas unitarias sino de integración/funcional, pero solo porque usted ejecuta el corrector de pruebas unitarias, no significa que deba ser una prueba unitaria. Si escribe pruebas funcionales/de integración basadas en la infraestructura de prueba de la unidad, obtendrá runner, informes, integración VS al igual que con la prueba unitaria, que es GRAN ganancia, especialmente si desea ejecutarla en el servidor CI, donde su prueba se ejecuta cada vez que se actualiza se implementa la compilación de la aplicación. – yoosiba

8

que estaba buscando esta misma cosa, y la respuesta de jvmenen me ayudó. Sin embargo, ha habido algunas actualizaciones de WatiN desde que se dio la respuesta, así que tuve que reescribir la clase de ayuda un poco para ser coherente con la última versión de WatiN (actualmente 2.0.20).

WatiN ya no contiene la función IE.AttachToIE, así que tuve que modificar eso un poco. Además, también hice la clase de ayuda utilizando genéricos, de modo que se puede usar cualquier tipo de navegador y no solo IE (creo que IE y Firefox son compatibles con WatiN ahora, y Chrome está por venir).

Así que en caso de cualquier otra persona está buscando para esto también, aquí está mi versión de la IEStaticInstanceHelper (ahora llamada 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(); 
    } 
} 

Espero que esto ayude a alguien :)

Cuestiones relacionadas