Compartir a través de


Este artículo proviene de un motor de traducción automática.

Ejecución de prueba

Módulo .NET pruebas con IronPython

James McCaffrey

Descarga de código de la Galería de código de MSDN
Examinar el código en línea

Contenido

El módulo en la prueba
Pruebas de ad hoc módulo interactivo
Automatización de prueba de módulo ligero
Ajustar hacia arriba

El lenguaje de secuencias de comandos Python tiene características que sea una opción excelente para llevar a cabo varios tipos de pruebas de software. Hay varias implementaciones de Python disponibles incluida CPython, la implementación más común en equipos que ejecutan sistemas operativos como de UNIX y IronPython, una implementación lanzado en 2006 en tiempo de ejecución que los objetivos de Microsoft .NET Framework. En la columna de este mes se demuestre cómo utilizar IronPython para probar módulos basadas en .NET desde ambos la línea de comandos de Python y en secuencias de comandos ligeros Python. Asumo que tenga alguna experiencia con un lenguaje de secuencias de comandos como JavaScript, Windows PowerShell, VBScript, Perl, PHP o Ruby, pero no suponga que tiene experiencia con Python. Eche un vistazo a la figura 1 para hacerse una idea de donde me punta. ESTOY utilizando IronPython realizar una prueba rápida y ad hoc de un método que compara dos manos de tarjeta en un módulo de .NET denominado TwoCardPokerLib. SE describen los comandos mostrados en la figura 1 con detalle más adelante en esta columna, pero por ahora observe que forma interactiva agregar una referencia a una DLL que aloja el módulo de .NET, crear instancias de los dos objetos disponible de ese módulo y se llama a un método de comparación para determinar si una mano late la mano de otra. Ahora eche un vistazo rápido en la figura 2 . Que captura de pantalla muestra la ejecución de una secuencia IronPython ligera que tardaba me sólo minutos para crear. De nuevo, vaya a través de todos los detalles más adelante, pero se puede ver que realizar pruebas al leer datos de casos de pruebas desde un archivo de texto de módulo clásico, crear instancias de los dos objetos de disponible desde el módulo TwoCardPokerLib, llame al método comparación y, a continuación, comparar los resultados reales con resultados esperados para determinar los resultados de aprobación o error de casos de pruebas.

Figura 1 pruebas ad hoc con IronPython en la línea de comandos

>>> import sys
>>> sys.path
['C:\\IronPython', 'C:\\IronPython\\Lib']
>>> sys.path.append(r'C:\ModuleTestingWithPython\TwoCardPokerLib\bin\  Debug')
>>> sys.path
['C:\\IronPython', 'C:\\IronPython\\Lib', 'C:\\ModuleTestingWithPython\\  TwoCardPokerLib\\bin\\Debug']
>>>
>>> import clr
>>> dir()
['_', '__builtins__', '__doc__', '__name__', 'clr', 'site', 'sys']
>>>
>>> clr.AddReferenceToFile("TwoCardPokerLib.dll")
>>> from TwoCardPokerLib import *
>>> dir()
['Card', 'Hand', '_', '__builtins__', '__doc__', '__name__', 'clr',   'site', 'sys']
>>>
>>> c1 = Card()
>>> c2 = Card("9d")
>>> print c1,c2
As 9d
>>>
>>> h1 = Hand(c1,c2)
>>> h2 = Hand("Ah","8c")
>>> expected = 1
>>> actual = h1.Compare(h2)
>>>
>>> if actual == expected: print "Pass\n",
... else: print "Fail\n"
...
Pass
>>>
>>> ^Z

C:\IronPython>

fig02.gif

La Figura 2 prueba de automatización con una secuencia de comandos IronPython

En las secciones que siguen, describiré la biblioteca de clase TwoCardPokerLib en el que se realiza la prueba para entenderá exactamente lo que se está probando. A continuación, HABLARÉ sobre los comandos de IronPython interactivos que utilizados en la figura 1 . A continuación presente y Explique en detalle la secuencia Python corta que genera el resultado en la figura 2 . El código fuente completo para el instrumento de prueba y la biblioteca en el que se realiza la prueba se encuentran en la descarga que acompaña a esta columna.

Le ajustar hacia arriba con una breve explicación de cómo puede adaptar y ampliar las ideas presentadas para satisfacer necesidades propias pruebas. Estoy seguro de que encontrará que la Python pruebas técnicas presentadas aquí será una excelente incorporación a su software de pruebas el conjunto de cualificaciones.

El módulo en la prueba

Ahora veamos la biblioteca en el que se realiza la prueba. Decidido crear una biblioteca de clase .NET para probar que tiene suficiente funcionalidad para mostrar los tipos de problemas que afrontar al realizar módulo real probar en un entorno de producción, pero no para problemas mucho complejidad que ocultan los detalles de la biblioteca las pruebas. Concebir un juego hipotético de dos tarjetas poker donde cada jugador recibe sólo dos tarjetas de cuatro, barajas estándar y 52 tarjeta. Esto conduce forma natural a un diseño orientado a objetos con una clase de tarjeta, una clase disponible y un método de comparación para determinar cuál de los dos objetos disponible es mejor. Decidí que cada mano dos tarjetas se podría clasificar como un vaciado recto (consecutivos tarjetas del mismo palo), un par (dos tarjetas con el mismo rango de) un vaciado (dos tarjetas del mismo palo), una seria (dos tarjetas consecutivos) y, a continuación, As máximos hasta cuatro alto. Tenga en cuenta que una mano tres máximos no es posible porque tres dos es una seria y As tres es un alto de ACE. Incluso dicho un ejemplo sencillo es en su lugar interesante para implementar. IronPython puede utilizarse para probar eficazmente bibliotecas .NET independientemente del lenguaje implementación, y IronPython puede utilizarse para probar las bibliotecas de COM clásicos. El código fuente para la clase de tarjeta en mi biblioteca TwoCardPokerLib se muestra la figura 3 .

Figura 3 la clase de tarjeta de la biblioteca de prueba

public class Card
{
  private string rank;
  private string suit;
  public Card() {
    this.rank = "A"; // A,2, . . ,9,T,J,Q,K
    this.suit = "s"; // c,d,h,s
  }
  public Card(string s) {
    this.rank = s[0].ToString();
    this.suit = s[1].ToString();
  }
  public override string ToString() {
    return this.rank + this.suit;
  }
  public string Rank {
    get { return this.rank; }
  }
  public string Suit {
    get { return this.suit; }
  }
  public static bool Beats(Card c1, Card c2) {
    if (c1.rank == "A") {
      if (c2.rank != "A") return true;
      else return false;
    }
    else if (c1.rank == "K") {
      if (c2.rank == "A" || c2.rank == "K") return false;
      else return true;
    }
    else if (c1.rank == "Q") {
      if (c2.rank == "A" || c2.rank == "K" || c2.rank == "Q") return false;
      else return true;
    }
    else if (c1.rank == "J") {
      if (c2.rank == "A" || c2.rank == "K" || c2.rank == "Q" || c2.rank == "J")
        return false;
      else
        return true;
    }
    else if (c1.rank == "T") {
      if (c2.rank == "A" || c2.rank == "K" || c2.rank == "Q" ||
        c2.rank == "J" || c2.rank == "T")
        return false;
      else return true;
    }
    else { // c1.rank is 2, 3, . . 9
      int c1Rank = int.Parse(c1.rank);
      int c2Rank = int.Parse(c2.rank);
      return c1Rank > c2Rank;
    }
  } // Beats()

  public static bool Ties(Card c1, Card c2) {
    return (c1.rank == c2.rank);
  }
} // class Card

Para mantener mi código breve y las ideas principales claro, han realizado algunos accesos directos que no toma en un entorno de producción, por ejemplo omitiendo todas las comprobaciones de error. Mi clase de tarjeta de forma intencionada se diseñó para ilustrar muchas de las características comunes de un módulo de .NET típica. Observe hay un constructor de tarjeta predeterminado, que crea una ACE del objeto de tarjeta de picas. Hay un constructor que acepta una cadena como TD para crear un objeto que representa un diez de diamantes tarjeta. Implementar propiedades de get exponer la clasificación y palo de un objeto de ficha. Y implementar métodos de pulsaciones y relaciones estáticos que pueden utilizarse para determinar si un objeto de tarjeta de pulsaciones o vincula la tarjeta de otro objeto. Mi clase disponible es demasiado larga para presentar en su totalidad por lo que describiré sólo las partes claves de la clase. La clase disponible tiene sólo dos campos de miembros:

public class Hand {
  private Card card1;
  private Card card2;
  // constructors, methods, etc.
}

Hago la suposición importante que card1 es el mayor de (o, posiblemente, igual a) los dos objetos de tarjeta. Esto simplifica enormemente la lógica de mi método Hand.Compare. Mi clase disponible tiene varios constructores, una situación típica que debe tener en cuenta al realizar pruebas de módulo. El constructor de disponible predeterminado crea una mano con dos tarjetas de picas de ace–of:

public Hand() {
  this.card1 = new Card(); 
  this.card2 = new Card();
}

Implementar dos otros constructores de disponible que me permiten a cualquier paso de tarjeta de dos objetos o las dos cadenas:

public Hand(Card c1, Card c2) {
  this.card1 = new Card(c1.Rank + c1.Suit);
  this.card2 = new Card(c2.Rank + c2.Suit);
}
public Hand(string s1, string s2) {
  this.card1 = new Card(s1);
  this.card2 = new Card(s2);
}

En la figura 4 implementar cuatro métodos auxiliares privados. Como verá, métodos privados no están expuestos a una secuencia de comandos de prueba IronPython.

Los métodos de privada en la figura 4

private bool IsPair() { return this.card1.Rank == this.card2.Rank; }
private bool IsFlush() { return this.card1.Suit == this.card2.Suit; }
private bool IsStraight() {
  if (this.card1.Rank == "A" && this.card2.Rank == "K") return true;
  else if (this.card1.Rank == "K" && this.card2.Rank == "Q") return true;
  // etc: Q-J, J-T, T-9, 9-8, 8-7, 7-6, 6-5, 5-4, 4-3, 3-2
  else if (this.card1.Rank == "A" && this.card2.Rank == "2") return true; 
  else return false;
}
private bool IsStraightFlush() { return this.IsStraight() &&
  this.IsFlush();
}

Como general regla general, cuando realizar módulo pruebas no explícitamente pruebas métodos privados. La idea es que los errores de métodos auxiliares se expondrán al probar el método público que utiliza el Ayudante. El método Hand.Compare es sorprendentemente complicado. Codificado métodos auxiliares pulsaciones y relaciones privados y se, a continuación, utilizarlas para implementar el método público de comparar:

public int Compare(Hand h) {
  if (this.Beats(h))
    return 1;
  else if (this.Ties(h))
    return 0;
  else if (h.Beats(this))
    return -1;
  else
    throw new Exception("Illegal path in Compare()");
}

Utilizo el antiguo paradigma de función strcmp(s,t) de lenguaje C para pulsaciones Hand.Compare—if el parámetro disponible "izquierdo" (el "Este" objeto) el parámetro "derecha" (explícito disponible parámetro de entrada), la comparación devuelve 1. Si el parámetro derecho pulsaciones el parámetro izquierdo comparación devuelve-1. Si los dos objetos de disponible son iguales de acuerdo con las reglas, comparación devuelve 0. La mayor parte del trabajo se realiza mediante el método pulsaciones privado, que se muestra en la figura 5 .

Figura 5 el método pulsaciones

private bool Beats(Hand h) {
  if (this.IsStraightFlush()) {
    if (!h.IsStraightFlush()) return true;
    if (h.IsStraightFlush()) {
      if (Card.Beats(this.card1, h.card1)) return true;
      else return false;
    }
  } // this.IsStraightFlush()
  else if (this.IsPair())
    // code  
  else if (this.IsFlush())
   //  code
  else if (this.IsStraight())
    // code    
  else 
    // code for Ace-high down to Four-high
  }

  return false;
}

El código para ritmos es de una página larga y puede comprobar los detalles si está interesada mediante el examen de la descarga de código que acompaña. Deliberadamente inserta un error de la lógica del método relaciones privado:

else if (this.IsFlush() && h.IsFlush() &&  
  this.card1.Rank == h.card1.Rank)          // error
    return true;

Si los dos objetos de mano que se comparan son ambos registros, a continuación, compruebe si dos manos tienen el mismo rango de la tarjeta de alto. Sin embargo no compruebe la segunda tarjeta de cada mano que debe:

else if (this.IsFlush() && h.IsFlush() &&  
  this.card1.Rank == h.card1.Rank &&
  this.card2.Rank == h.card2.Rank)         // correct
    return true;

Este error lógica genera el error de caso de prueba que se muestra en la figura 2 . Mi biblioteca creado por el uso de Visual Studio para crear un proyecto de biblioteca de clases denominado TwoCardPokerLib en TestingWithPython C:\Module, lo que un archivo TwoCardPokerLib.dll en C:\ModuleTestingWithPython\TwoCardPokerLib\bin\Debug.

Pruebas de ad hoc módulo interactivo

Ahora veamos cómo puede examinar y probar bibliotecas .NET mediante IronPython. En concreto, echemos un vistazo a cada uno de los comandos mostrados en la captura de pantalla en la figura 1 . La primera parte del resultado que se muestra en la figura 1 indica que ESTOY utilizando versión 1.1.1 de IronPython.

IronPython es una descarga gratuita disponible en CodePlex, el proyecto de código fuente abierto patrocinados por Microsoft, en codeplex.com/IronPython. Requiere la versión 2.0 de .NET Framework y se ejecuta en cualquier equipo que admita esa versión de Framework. ESTOY utilizando Windows Vista. Realmente no instala IronPython, sino simplemente descargar un solo archivo en zip en el equipo y extraer su contenido en ningún directorio adecuada. En mi caso almacena todo el IronPython archivos y subdirectorios en C:\IronPython. Invoca el intérprete de línea de comandos de Python (ipy.exe) y se especifica una opcional - X: argumento de TabCompletion para habilitar la finalización de la ficha. Si escribe ipy.exe -h obtendrá una lista de todas las opciones. Cuando se inicia IronPython, ejecutará una secuencia de comandos inicio especial, denominada site.py, si existe una secuencia de comandos. He usado el archivo site.py estándar que viene con IronPython, sin modificaciones.

Después de IronPython, examine la información actual que IronPython del sistema ruta de acceso:

>>> import sys
>>> sys.path
['C:\\IronPython', 'C:\\IronPython\\Lib']

En primer lugar ejecute un comando de importación sys por lo que tiene acceso a los métodos dentro del módulo de sistema IronPython especial. A continuación muestra la lista de rutas de acceso que se examinan IronPython al buscar archivos que no están en el directorio actual. Puede considerar esto como un mecanismo IronPython local que es algo similar a la variable de entorno ruta de acceso de Windows del sistema operativo. Ya que invoca IronPython con la característica TabCompletion, si desea saber qué propiedades y métodos están disponibles para mí desde el módulo de sistema, podría escribió sys. y presione la tecla <tab> repetidamente. A continuación sé IronPython donde se encuentra el módulo .NET en el que se realiza la prueba:

>>> sys.path.append(r'C:\ModuleTestingWithPython\TwoCardPokerLib\bin\Debug')
>>> sys.path
['C:\\IronPython', 'C:\\IronPython\\Lib', 'C:\\ModuleTestingWithPython\\TwoCardPokerLib\\bin\\Debug']

Utilice el método path.append del módulo de sistema para agregar un directorio nuevo a la lista de búsqueda IronPython. Observe el carácter r delante del argumento de cadena que se va a anexar. En Python pueden utilizar comillas único o comillas dobles alrededor de las cadenas. Sin embargo, a diferencia de algunos idiomas, Python evaluará caracteres de escape, como \n dentro de las cadenas entre comillas único y entre comillas dobles. Para asegurarse de que se interpreta una cadena estrictamente como un literal (una cadena "original" en la terminología de Python) se puede utilizar el modificador de r como ha hecho anteriormente. Después de anexar el nuevo directorio Compruebe no que los errores de escritura por emitir un comando sys.path. A continuación prepare cargar la DLL en el que se realiza la prueba por primero habilitar métodos que pueden cargar los módulos de .NET:

>>> import clr
>>> dir()
['_', '__builtins__', '__doc__', '__name__', 'clr', 'site', 'sys']

Emite un comando de clr (para common language runtime) de importación y ahora tienen acceso para el módulo de clr, que tiene varios métodos que pueden cargar los ensamblados de .NET. A continuación, utilice el comando Python dir() para ver qué módulos actualmente tienen acceso a. Tenga en cuenta que no es actualmente necesario acceso a la biblioteca TwoCardPokerLib. Ahora puede usar el módulo de clr para tener acceso a la biblioteca en el que se realiza la prueba:

>>> clr.AddReferenceToFile("TwoCardPokerLib.dll")
>>> from TwoCardPokerLib import *
>>> dir()
['Card', 'Hand', '_', '__builtins__', '__doc__', '__name__', 'clr', 'site', 'sys']

Utilice el método AddReferenceToFile para habilitar el entorno IronPython actual llamar a la DLL TwoCardPokerLib. Python distingue mayúsculas de minúsculas, por lo que si hubieran escrito addreferencetofile, por ejemplo, no se ha llegado un error de, como por ejemplo, de atributo (método).

Después de agregar una referencia al módulo en el que se realiza la prueba, es necesario utilizar la instrucción de importación para hacer que el módulo estén disponibles. Puede tener con importación TwoCardPokerLib pero al escribir en la importación de TwoCardPokerLib * en su lugar. Si utiliza el formulario primero, más fácil, podría tengo que cualifique totalmente todo en el módulo, TwoCardPokerLb.Hand por ejemplo, en lugar de simplemente escribir disponible. El formulario de-<module> de importación de <classes> del comando de importación permite que omite el nombre del módulo principal cuando se escribe. Observe que después de hacer un comando dir(), comprueba que las clases de ficha y disponible dentro del módulo TwoCardPokerLib están ahora disponibles para mí. Ahora puede ejercer el módulo en el que se realiza la prueba creando dos objetos de tarjeta:

>>> c1 = Card()
>>> c2 = Card("9d")
>>> print c1,c2
As 9d

Utilice el constructor de tarjeta de predeterminado para crear instancias de un objeto denominado c1. Recuperar de la sección anterior que el constructor de tarjeta predeterminado crea una ACE del objeto de picas. Utilice el constructor de tarjeta no predeterminado para crear un objeto que representa un nueve de diamantes. Observe que no utiliza una palabra clave como "nuevo" para crear instancias de objetos que haría en algunos idiomas. Si había utiliza la anterior de instrucción corta "importar TwoCardPokerLib", se ha llamado al constructor como " c1 = TwoCardPokerLib.Card() ". Utilice la intrínseca instrucción de impresión de Python para mostrar mis dos objetos de tarjeta. En segundo plano, la instrucción de impresión IronPython realmente es llamar al método Card.ToString() que he implementado en la biblioteca de clase. Ahora crear instancias de los dos objetos disponible y llamar al método Hand.Compare:

>>> h1 = Hand(c1,c2)
>>> h2 = Hand("Ah","8c")
>>> expected = 1
>>> actual = h1.Compare(h2)  

Pasar los dos objetos de tarjeta que recién creado en un constructor de disponible para crear una primera mano, y utilizamos la versión de cadena de parámetro de constructor para crear instancias de una mano de segundo. Porque una mano de ACE de nueve late una mano de ACE de ocho, CREO que el método de comparación para devolver 1 para el almacenar dicho valor en una variable denominada esperada. Observe que Python es un lenguaje escrito dinámicamente, por lo que no declarar tipos de datos. Llamar al Hand.Compare método y el resultado de almacén en una variable denominada real. Pueden ver los métodos disponibles en la clase disponible escribiendo a mano. en la línea de comandos y, a continuación, presionar la tecla <tab>. Podrían vea los métodos públicos, como comparar y ToString pero no podrían ver métodos privados como pulsaciones y relaciones. Ahora puede determinar un resultado de la aprobación o error para mi prueba interactivo ad hoc:

>>> if actual == expected: print "Pass\n",
... else: print "Fail\n"
...
Pass
>>>

La sintaxis de if-then de Python en una línea de comandos es un poco extraño, por lo que lo explicaré en la sección siguiente. Pero básicamente comprueba si el valor de la variable denominada real es igual al valor en la variable denominada esperada. Si es así, muestra un mensaje de "paso"; en caso contrario, se imprime "error". Observe que ha incluido un carácter de nueva línea de cada cadena. La respuesta "..." intermedios del intérprete IronPython indica que tiene un comando incompleto y el intérprete está esperando que completar el comando.

Automatización de prueba de módulo ligero

Ahora veamos cómo escribir IronPython ligeros scripts para probar las bibliotecas de clases de .NET. La secuencia de comandos en la figura 6 genera el resultado que se muestra en la figura 2 .

Figura 6 archivo harness.py

# harness.py
# test TwoCardPokerLib.dll using data in TestCases.txt

print "\nBegin test run\n"
import sys
print "Adding location of TwoCardPokerLib.dll to sys.path"
sys.path.append(r'C:\ModuleTestingWithPython\TwoCardPokerLib\bin\Debug')

import clr
print "Loading TwoCardPokerLib.dll\n"
clr.AddReferenceToFile("TwoCardPokerLib.dll")
from TwoCardPokerLib import *

print "=================================="
fin = open("TestCases.txt", "r")
for line in fin:
  if line.startswith("$"):
    continue
  (caseID,input,method,expected,comment) = line.split(':')
  expected = int(expected)
  (left,right) = input.split(',')
  h1 = Hand(left[0:2],left[2:4])
  h2 = Hand(right[0:2],right[2:4])
  print "Case ID = " + caseID
  print "Hand1 is " + h1.ToString() + "   " + "Hand2 is " + h2.ToString()
  print "Method = " + method + "()"
  actual = h1.Compare(h2)

  print "Expected = " + str(expected) + " " + "Actual = " + str(actual)
  if actual == expected:
    print "Pass"
  else:
    print "** FAIL **"


  print "=================================="

fin.close()
print "\nEnd test run"
# end script

Comienzo mi script de instrumento de prueba IronPython con comentarios:

# harness.py
# test TwoCardPokerLib.dll using data in TestCases.txt

El símbolo # es el carácter comentario para las secuencias de comandos Python. Python es la línea de basado, por lo que los comentarios ejecutar hasta el final de una línea. Python también admite los comentarios multilínea con triple solo las cotizaciones. Las secuencias de comandos Python utilizan una extensión de archivo .PY y pueden crearse con cualquier editor de texto, incluido el bloc de notas. Mi instrumento de prueba lee datos de casos de pruebas de un archivo externo denominado TestCases.txt:

0001:AcKc,AdAs:Compare:1:  "royal flush" > pair Aces
0002:Td9d,Th9h:Compare:0:  straight flush diamonds == straight flush hearts
$0003:Ah2c,As9c:Compare:1:   straight > Ace high
0004:9h6h,9d7d:Compare:-1:  flush 9-6 high < flush 9-7
0005:KcJh,As5d:Compare:-1: King high < Ace high

Aquí en el tener sólo cinco casos de prueba, pero en un escenario de producción podrían tener cientos o miles. Hay 7,311,616 o 524 entradas legales para Hand.Compare, que ilustra el impracticality de pruebas exhaustively módulos incluso simples.

Cada línea representa un único caso de prueba. Cada campo está delimitado por el carácter de dos puntos. El primer campo es un identificador de caso de prueba. El segundo campo es una cadena que contiene la información de dos objetos disponible, separados por un carácter de coma. El tercer campo indica qué método para probar. El cuarto campo es el valor esperado. El quinto campo es opcional y es un comentario de casos de pruebas. Caso de prueba aviso 0003 va precedido por un carácter $. VOY a buscar este carácter en mi instrumento de prueba y omitir cualquier tales casos de prueba. Caso de prueba 0004 genera un resultado de error debido del error lógica deliberados (únicamente para la demostración) que coloca en el método Hand.ties que se llama al método Hand.Compare en el que se realiza la prueba. Almacenar datos de casos de pruebas en un archivo de texto es rápido y fácil. Puede también han incrustar mis datos de casos de pruebas directamente en el instrumento o almacenan Mis casos en un archivo XML y así sucesivamente. Python puede controlar fácilmente cualquier esquema de almacenamiento de casos de pruebas. A continuación mostrar un mensaje el shell de comandos:

print "\nBegin test run\n"

Debido a cadenas Python pueden delimitarse mediante dobles comillas o comillas simples, y caracteres de escape se evalúan en ambos estilos de cotización, la elección entre tipos de cotización es realmente una cuestión de preferencias. Suelen utilizar comillas dobles excepto cuando voy para usar el modificador r para hacer que la cadena un literal, en cuyo caso tienden a utilizar comillas simples. A continuación mi script de instrumento de prueba Python agrega la ubicación de la DLL en el que se realiza la prueba al trazado del sistema Python:

import sys
print "Adding location of TwoCardPokerLib.dll to sys.path"
sys.path.append(r'C:\ModuleTestingWithPython\TwoCardPokerLib\bin\Debug')

Aquí se codificar la ubicación de la DLL en el que se realiza la prueba. Pueden pasar argumentos de línea de comandos a la secuencia de comandos python y acceso a ellos con la matriz sys.argv integrado. Por ejemplo, si invocar la secuencia de comandos

  > ipy.exe   harness.py   C:\Data   MyLib.dll

a continuación, sys.argv[0] podría contener el nombre de la secuencia de comandos (harness.py), sys.argv[1] podría contener el primer argumento (C:\Data) y sys.argv[2] podría contener el segundo argumento (MyLib.dll). A continuación indique el instrumento para cargar el módulo en el que se realiza la prueba:

import clr
print "Loading TwoCardPokerLib.dll\n"
clr.AddReferenceToFile("TwoCardPokerLib.dll")
from TwoCardPokerLib import *

Hay varias formas para cargar una biblioteca .NET-based mediante IronPython. El método de clr.AddReferenceToFile es sencilla y efectiva cuando los sys.path contiene la ubicación de la biblioteca para agregar, pero el módulo de clr también contiene alternativas incluidos clr.AddReference, clr.AddReferenceByName, clr.AddReferenceByPartialName y clr.AddReferenceToFileAndPath. Aquí se usa el * comodín para cargar todas las clases de la biblioteca TwoCardPokerLib, pero pueden cargar clases específicas por los nombres. Python tiene varias formas para procesar un texto archivo línea por línea. Utilice la función abierto de archivo intrínsecos y pasar, el nombre de mi archivo de caso de prueba y un argumento r para indicar que está abriendo el archivo para leer:

print "=================================="
fin = open("TestCases.txt", "r")
for line in fin:
  # process line here

Otros modos comunes incluyen w para escribir en él y una para anexar. El argumento modo de es opcional y valor predeterminado es r por lo que podría han dejado fuera. Una buena referencia para características de lenguaje Python, sintaxis y funciones intrínsecas puede figura en docs.python.org. El resultado de la función abierto es un identificador de archivo que asigne a una variable denominada fin. A continuación, utilice un bucle recorrer en línea por línea. Con el nombre la línea de almacenamiento variable "línea", no obstante podría haber usado cualquier nombre de variable válido. Observe una peculiaridad sintáctica de Python: en lugar de utilizar símbolos de empezar a fin como {. .. } o inicial. .. cliente como la mayoría de los pendientes de idiomas, Python utiliza el carácter de dos puntos en conjunción con sangría para indicar el comienzo y fin de bloques de instrucciones. Dentro de mi bucle de procesamiento principal, utilice la función de cadena startswith intrínseco para comprobar si la línea actual de mi archivo de caso de prueba empieza con un carácter de signo de dólar:

if line.startswith("$"):
  continue

Si encuentra un signo $, usar la instrucción continue para omitir las instrucciones restantes en el bucle y la línea siguiente de mi archivo de casos de pruebas de lectura. Python tiene un conjunto completo de estructuras de control de bucle y toma de decisiones. A continuación analizar la línea de datos de casos de pruebas en sus campos individuales:

(caseID,input,method,expected,comment) = line.split(':')
expected = int(expected)

Utilizo una nueva característica de Python denominado una tupla y la función de cadena división intrínseco para analizar rápidamente los datos. Puede realizar la tarea con un enfoque tradicional de matriz como vea a continuación, aunque CREO que el enfoque de tupla Python es más corto y fáciles de entender.

tokens = line.split(':')
caseID = tokens[0]
input = tokens[1]
method = tokens[2]
expected = tokens[3]
comment = tokens[4]

Utilice la función de int() para convertir explícitamente la variable denominada esperada de cadena de tipo al tipo int que pueden comparar espera con real. Otras funciones de conversión de tipo útil incluyen str(), float(), long() y bool(). A continuación realizar una segunda operación de análisis para extraer las dos manos de entrada:

(left,right) = input.split(',')
h1 = Hand(left[0:2],left[2:4])
h2 = Hand(right[0:2],right[2:4])

Después de mi primer análisis con la división, la entrada variable contiene un valor de cadena como KcJh, As5d. Por lo tanto, LLAMO a dividir de nuevo con un argumento y almacenar los dos resultados en las variables denomina hacia la izquierda y derecha. Ahora KcJh de suspensiones de la variable de cadena denominada izquierda y derecha suspensiones As5d. A diferencia de muchos lenguajes posibles, Python no tiene un método de subcadena. En su lugar, Python utiliza la indización de matriz para extraer las subcadenas. Matriz de indización empieza en 0, por lo que si la variable a la izquierda contiene KcJh, a continuación, la expresión deja [0: 2] proporciona kc y la expresión izquierda proporciona [2:4] Jh. Tenga en cuenta para extraer una subcadena de una cadena más grande, especificar el índice del primer carácter en la mayor cadena (como es de esperar) pero uno más que el índice del carácter final. Una vez que tenga cadenas que representan las tarjetas individuales, pasa al constructor disponible. A continuación eco mis datos de entrada al shell:

print "Case ID = " + caseID
print "Hand1 is " + h1.ToString() + "   " + "Hand2 is " + h2.ToString()
print "Method = " + method + "()"

Python utiliza el carácter para realizar la concatenación de cadenas, por lo que en las tres instrucciones de impresión anteriores estoy imprimir tres cadenas +. La función de impresión puede aceptar varios argumentos separados por el, carácter por lo que ha pudo escriben instrucciones como las siguientes acciones para producir el mismo resultado:

print "Case ID = " , caseID

Ahora estoy listo para llamar al método en el que se realiza la prueba:

actual = h1.Compare(h2)
print "Expected = " + str(expected) + " " + "Actual = " + str(actual)

Tenga en cuenta que dado que implementa el método Hand.Compare como un método de instancia, llamarlo desde el contexto del objeto h1 disponible. Si había codificado compartir como un método estático se ha llamado a, así:

actual = Compare(h1,h2)

Observe que en este momento las variables de reales y esperadas son de tipo int porque real es el valor devuelto del método de comparación que está definido para devolver un int y espera se convertir explícitamente a un int. Por tanto, convierte real y espera a cadenas para que puede concatenar una cadena de salida único. Ahora mostrar el resultado de aprobación o error de caso de prueba:

if actual == expected:
  print "Pass"
else:
  print "** FAIL **"

print "=================================="

Python utiliza sangría para indicar el principio y el final del bloque de instrucciones. Si tiene mucha experiencia en programación en otros idiomas, puede parecer un poco extraño uso del Python de sangría en primer lugar. Pero la mayoría de los evaluadores ha hablado para indicar que los problemas de sintaxis inusual del Python familiarizarse muy rápidamente.

Si desea mantener un seguimiento del número total de casos de prueba que pasa, pueden inicializar los contadores fuera el bucle de procesamiento principal así:

numPass = numFail = 0

y, a continuación, modifique la estructura if-then:

if actual == expected:
  numPass += 1
  print "Pass"
else:
  numFail += 1
  print "** FAIL **"

A continuación, pueden imprimir mis resultados fuera del bucle de procesamiento:

print "Num pass = " , numPass ,  " num fail = " ,  numFail

Tenga en cuenta que Python no admite la sintaxis numPass ++ o ++ numPass para incrementar una variable de int. Aquí tan sólo me imprimir resultados para el shell de comandos, pero pueden escribir fácilmente los resultados en un archivo de texto, archivo XML, base de datos de SQL o otro almacenamiento. Ahora terminar mi instrumento de prueba hasta:

fin.close()
print "\nEnd test run"
# end script

Cierra la referencia de archivo caso de prueba para liberar el identificador de archivo e imprimir un mensaje que indica que la prueba está completa. La estructura de secuencia de comandos es muy sencilla pero Python tiene características que permiten administrar compleja. Por ejemplo, en un entorno de producción debe ajustar definitivamente mi script completo en un controlador de excepciones:

try
  # harness code here
except
  # handle any exceptions here 

Además, Python admite funciones de definidos de programador, por lo que podría han estructurado mi instrumento como una función principal más funciones auxiliares.

Ajustar hacia arriba

Prueba automatizada módulo es posiblemente el tipo más importante de automatización de prueba de software. Siempre desee evaluar la idoneidad de un lenguaje de programación para la prueba de automatización, primero compruebo grado el idioma ocupa pruebas de módulo. En mi opinión, IronPython pasa esta prueba litmus con flying colors. No es perfecto para todas las tareas y escenarios pruebas ningún lenguaje de programación. Dicho esto, IronPython tiene muchas características que facilitan una elección excelente como un lenguaje pruebas del módulo.

Permitirme fin por mencionar la automatización de prueba de módulo cómo ligero con IronPython está relacionado con las pruebas unitarias. Las pruebas unitarias con marcos como NUnit más a menudo se colocan directamente en el código del módulo. Desarrollo controlado por pruebas gracias a las pruebas unitarias es principalmente una actividad de desarrollador. Mediante un enfoque de pruebas de unidad durante el desarrollo no absolve, de la responsabilidad de realizar pruebas de módulo completa y dedicado. Aquí es donde entra Python en. En otras palabras, módulo de pruebas con Python es un complemento para, no un sustituto para, las pruebas unitarias. Cuando los dos métodos se utilizan conjuntamente puede producir software mejor y más confiable.

Envíe sus preguntas y comentarios para James a testrun@Microsoft.com.

Dr. James McCaffrey funciona para información biológicas volt, Inc., que administra el entrenamiento técnico para ingenieros de software trabaja en Microsoft. Ha trabajado en varios productos de Microsoft como Internet Explorer y MSN Search. Juan es el autor de .NET Test Automation Recipes. Puede ponerse en jmccaffrey@volt.com o v-jammc@microsoft.com.