Este artículo proviene de un motor de traducción automática.
Ejecución de pruebas
Pruebas en pares con QICT
James McCaffrey
Descargar el ejemplo de código
Un conocimiento sólido de desunidas par a par pruebas principios es esencial para todos los evaluadores de software, los desarrolladores y administradores. En la columna de este mes, he explique exactamente qué desunidas par a par pruebas son y ofrecer código fuente completo de C# para una calidad de producción desunidas par a par pruebas herramienta denominada QICT. En resumen, desunidas par a par pruebas son una técnica que permite reducir un conjunto de entradas del caso de prueba a un conjunto mucho más pequeño que es probable que revelar errores en el sistema de prueba grande y difícil de administrar. La mejor forma para explicar las pruebas desunidas par a par y mostrarle mi objetivo en este artículo, es por medio de dos capturas de pantalla. Considere la aplicación ficticia basado en Windows Forms que se muestra en de figura 1. La aplicación tiene cuatro parámetros de entrada. El primer parámetro es un control TextBox que puede aceptar “ a ” o “ b ”. El segundo parámetro es un grupo de controles RadioButton que puede tomar un valor de “ c ”, “ d ”, “ e ” o “ f ”. El tercer parámetro es un control ComboBox que puede tomar un valor de “ g, ” “ h ” o “ i ”. El cuarto parámetro es un control CheckBox que toma un valor de “ j ” o “ k ”. Por lo que sería un conjunto de entrada en caso de prueba {“ un ”, “ c ”, “ g ”, “ j ”}. La aplicación ficticia tiene un total de 2 * 4 * 3 * 2 = 48 posible entrada conjuntos, que es ciertamente manejable. Pero imagine una aplicación de reproducción de tarjeta de algún tipo con cinco parámetros, donde cada parámetro puede adoptar uno de los valores de 52 (para representar una tarjeta de una baraja de cartas, con sustitución normal). En esta situación habría 52 * 52 * 52 * 52 * 52 = 380,204,032 posibles conjuntos, de entrada que es probable que sea difícil de administrar a menos que se puede generar mediante programación los valores esperados para cada prueba de conjunto de entrada.
Figura 1 de aplicación de prueba A con cuatro parámetros de entrada
La idea de desunidas par a par pruebas es generar una lista de conjuntos de prueba que capturar a todos los pares de valores de parámetro de cada parámetro posibles. En el ejemplo que se muestra en de figura 1, hay un total de 44 tales entradas pares:
(a,c), (a,d), (a,e), (a,f), (a,g), (a,h), (a,i), (a,j), (a,k), (b,c), (b,d), (b,e), (b,f), (b,g), (b,h), (b,i), (b,j), (b,k), (c,g), (c,h), (c,i), (c,j), (c,k), (d,g), (d,h), (d,i), (d,j), (d,k), (e,g), (e,h), (e,i), (e,j), (e,k), (f,g), (f,h), (f,i), (f,j), (f,k), (g,j), (g,k), (h,j), (h,k), (i,j), (i,k)
Ahora el conjunto de pruebas {“ un ”, “ c ”, “ g ”, “ j ”} captura seis 44 pares de: (, c) (a, g), (a, j), (c, g), (c, j) y (g, j). El objetivo de generación de prueba en pares establecido es generar una colección de conjuntos de prueba que capturar a todos los pares de 44. Eche un vistazo a la captura de pantalla en de figura 2.
Figura 2 de prueba en pares Set generación con la herramienta de QICT
La captura de pantalla muestra una herramienta denominada qict.exe generar una colección de conjuntos de prueba 12 que capturar a todos los 44 pares de entrada para el escenario que se muestra en de figura 1. Si realiza un seguimiento a través de cada par de valores en los 12 conjuntos de prueba generados en de figura 2, verá que en realidad capturar a todos los pares de 44 enumerados anteriormente. Por lo que en esta situación, hemos reducido nuestras posibles entradas del caso de prueba de casos de prueba de 48 a 12 casos de prueba. Los ahorros no son muy importantes para este pequeño ejemplo, pero como mostraré en un momento, la utilizando desunidas par a par pruebas puede reducir drásticamente el número de entradas del caso de prueba en muchas situaciones. La suposición de desunidas par a par pruebas subyacente es que los errores de software con más frecuencia se encuentran en el código que implica la interacción de los valores de parámetros diferentes que en el código que implica valores desde dentro de un parámetro determinado. En otras palabras, para la aplicación ficticia en de figura 1, código de aplicación que trata con entradas “ a g ” y “ ” es más probable que introducir un error de lógica que el código que trata con entradas “ a b ” y “ ”. Se trata de una noción que, de hecho, admite algunos investigación.
Mediante la herramienta PICT
Hay varias herramientas de generación de prueba en pares conjunto disponibles para usted. Mi herramienta favorita en la mayoría de las situaciones es la herramienta PICT (en pares Independent combinatorio pruebas). PICT fue escrito por mi compañero Jacek Czerwonka, quién había adaptado código desde una herramienta en pares internos de Microsoft existente. PICT está disponible como descarga gratuita desde varias ubicaciones, incluida la página Centro de evaluadores de Microsoft en msdn.microsoft.com/testing/bb980925.aspx de. Si busca en Internet, también encontrará que varios otro prueba en pares establece herramientas de generación. Sin embargo, PICT es un único archivo ejecutable que se ejecuta desde una línea de comandos de shell. PICT es muy rápido y muy eficaces y debe cumplir las desunidas par a par pruebas necesita en la mayoría de las situaciones. Denominé la herramienta presentada en este artículo QICT (que no sustituir cualquier cosa en particular) para confirmar la importancia de la herramienta PICT.
¿Por qué es así, aún otra prueba en pares establece generador? Hay varias razones. En primer lugar, aunque PICT es una herramienta maravillosa, está escrito en código C++ nativo y el código fuente no está disponible. La herramienta QICT presentada aquí es, por lo que se pueda saber, la primera herramienta en pares de calidad de producción escrita con código administrado C#. La disponibilidad del código permite modificar libremente QICT para satisfacer sus necesidades. Por ejemplo, puede modificar QICT leer directamente su entrada de un archivo XML o una base de datos SQL, o puede modificar QICT para emitir directamente resultados en un formato de resultados personalizados. Y quizás desee experimentar con lógica la herramienta de la, digamos, por ejemplo, mediante la introducción de las restricciones (prueba entrada conjuntos que no están permitidos), mediante la introducción de conjuntos de prueba requerida, o cambiar cómo la herramienta genera su prueba establece la colección. Además, la disponibilidad de código fuente QICT permite la que copia y el lugar en pares probar código de generación establecido directamente en una herramienta de prueba o de aplicación de .NET. Por último, aunque el código fuente para algunas herramientas de generación de prueba en pares conjunto está disponible en Internet, algunas de estas herramientas son bastante ineficiente. Por ejemplo, considere una situación con 20 parámetros, cada uno de los cuales tiene 10 valores. Para este escenario hay 10 * 10 * 10 *. . . * 10 (20 veces) = 1020 = 100,000,000,000,000,000,000 posibles entradas de caso de prueba. Se trata de un lote de casos de prueba. La herramienta PICT Esto reduce a 217 sólo conjuntos de prueba en pares, y la herramienta QICT genera 219 o 216 conjuntos de prueba (según el valor de inicialización de un generador de números aleatorios, como explicaré en breve). Sin embargo, uno ampliamente referencia herramienta escrita en Perl produce 664 conjuntos de generación establecido de prueba en pares. Por último, con el código de origen QICT disponible y la explicación de este artículo de los algoritmos utilizados, puede adaptada QICT para otros lenguajes, como Perl, Python, Java o JavaScript si lo desea.
La herramienta de QICT
El código para la herramienta QICT es ligeramente demasiado largo para presentar en su totalidad en esta columna, pero el código fuente completo está disponible desde la Galerie de code MSDN en code.msdn.microsoft.com. Describiré los algoritmos y estructuras de datos que utilizar, junto con fragmentos de código de tecla, por lo que tendrá suficiente información para utilizar y modificar QICT según sea necesario. La esencia del funcionamiento de QICT es generar un conjunto de prueba a la vez, mediante algoritmos avariciosos para colocar cada valor de parámetro, hasta que todos los pares posibles se han capturado. El algoritmo de alto nivel para QICT se presenta en de figura 3.
Figura 3 de algoritmo QICT
read input file
create internal data structures
create an empty testset collection
while (number of unused pairs > 0)
for i := 1 to candidate poolSize
create an empty candidate testset
pick the "best" unused pair
place best pair values into testset
foreach remaining parameter position
pick a "best" parameter value
place the best value into testset
end foreach
end for
determine "best" candidate testset
add best testset to testset collection
update unused pairs list
end while
display testset collection
La clave para implementar este algoritmo de alto nivel es determinar qué tipo de estructuras de datos para utilizar y cuáles son las distintas opciones “ mejores ”. El código fuente QICT comienza así:
static void Main(string[] args)
{
string file = args[0];
Random r = new Random(2);
int numberParameters = 0;
int numberParameterValues = 0;
int numberPairs = 0;
int poolSize = 20;
Codifiqué QICT utilizando un estilo tradicional del procedimiento, en vez de tomar un enfoque orientado a objetos, por lo que puede refactorizar más fácilmente QICT para idiomas con compatibilidad limitada de OOP, como Perl y JavaScript. Leí primero un archivo de entrada desde la línea de comandos. Como puede ver, para mantener mi código limpio y sencillo, he dejado fuera normal comprobación de errores es posible que desee incluir. El archivo de entrada para QICT es el mismo que el utilizado por PICT, un archivo de texto simple que tiene el siguiente aspecto:
Param0: a, b
Param1: c, d, e, f
etc..
Los nombres de parámetro van seguidos de un carácter de dos puntos y una lista delimitada por comas de los valores válidos para ese parámetro. Valores de parámetro deben ser distintos. A continuación, crear instancias de un objeto Random. La elección de un valor de inicialización de 2 es arbitraria, pero cualquier valor hará que producen el mismo resultado para un conjunto de entrada cada vez que se ejecute QICT. Explicaré en breve el propósito del objeto número pseudoaleatorio. Declaro tres variables int que se asignará valores cuando se lee el archivo de entrada. En el ejemplo que se muestra en de figura 2, numberParameters es 4, numberParameterValues es 11 y numberPairs es 44. La variable poolSize almacena el número de conjuntos de prueba de candidato para generar para cada conjunto de pruebas. Si experimenta con QICT un poco, verá que la herramienta se ve afectada de forma bastante sorprendentemente secundaria ajustando el valor para poolSize. El corazón de QICT es la declaración de las estructuras de datos principal. Los cuatro primeros objetos son:
int[][] legalValues = null;
string[] parameterValues = null;
int[,] allPairsDisplay = null;
List<int[]> unusedPairs = null;
El objeto legalValues es una matriz escalonada donde cada celda a su vez contiene una matriz de valores int. La matriz legalValues contiene una representación en memoria del archivo de entrada, por lo que la celda 0 de valores legales contiene una matriz que contiene a su vez los valores 0 (para representar el valor del parámetro “ un ”) y 1 (para representar “ b ”). Resulta que trabajar directamente con los valores de cadena es bastante ineficiente y que representan valores de parámetro como enteros produce rendimiento significativamente más rápido. La matriz de cadena parameterValues contiene los valores de parámetro real y se utiliza al final de QICT para mostrar resultados como cadenas en lugar de ints. Por tanto, para el ejemplo anterior, celda 0 contiene “ un k ”, 1 de la celda contiene “ b ” y así sucesivamente hasta 10, de la celda que contiene “ ”. El objeto allPairsDisplay es una matriz bidimensional de ints. Se rellena por todos los pares posibles. En nuestro ejemplo, [0,0] de la celda contiene 0 (para “ un ”) y celda suspensiones [0,1] 2 (para “ c ”), el primer par posible. Celda [1,0] contiene 0 y celda suspensiones [1,1] 3 para representar el segundo par (a, d). El objeto unusedPairs es una lista genérica de matrices de int. El primer elemento de unusedPairs inicialmente es {0,2}. Utilizo una colección List para unusedPairs en lugar de una matriz porque cada vez que se agrega un nuevo conjunto de prueba a la prueba establece la colección, puedo quitar los pares generados por la nueva prueba establecer desde unusedPairs. Además, esto significa que tengo una condición de detención cómodo que se producirá cuando unusedPairs.Count llega a 0.
Las siguientes cuatro estructuras de datos de programa principal son:
int[,] unusedPairsSearch = null;
int[] parameterPositions = null;
int[] unusedCounts = null;
List<int[]> testSets = null;
Más desunidas par a par pruebas las herramientas de generación de conjunto, incluyendo QICT, realizar un gran número de búsquedas. Un enfoque de búsqueda eficaz es crucial para un rendimiento aceptable. Aquí declaro una matriz bidimensional denominada unusedPairsSearch. Es una matriz cuadrada con tamaño numberParameterValues por numberParameterValues, donde cada celda contiene un 1 si no se ha utilizado el par correspondiente y un 0 si el par correspondiente se ha utilizado o no es un par válido. Inicialmente, las tres primeras filas de unusedPairsSearch para el ejemplo en la figura 2 son:
0 0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 1 1 1 1 1
Y así sucesivamente.
Por lo que la fila uno significa pares (0,0) y (0,1) — es decir, (un, un) y (a, b): no son válidas, mientras pares (0,2), (0,3). . . (0,10) — es decir (, c) (a, d) a través (un, k): no captura aún por un conjunto de pruebas. La matriz parameterPositions contiene la ubicación dentro de un conjunto de prueba de un valor de parámetro especificado. Después de la inicialización de esta matriz contiene valores:
0 0 1 1 1 1 2 2 2 3 3
El índice de parameterPositions representa un valor de parámetro y el valor de celda correspondiente representa su posición en un conjunto de pruebas. Por tanto, la cuarta celda de la izquierda tiene índice = 3 y valor = 1, lo que significa que el valor del parámetro 3 (“ d ”) pertenece en la posición 1 (la ranura de segunda) en un conjunto de pruebas. El objeto unusedCounts es una matriz unidimensional que contiene el número de veces que un valor de parámetro en particular aparece en la matriz unusedPairs. Inicialmente unusedCounts contiene:
9 9 7 7 7 7 8 8 8 9 9
El índice representa un valor de parámetro y el valor de celda correspondiente es el recuento no utilizado. Por tanto, la cuarta celda de la izquierda tiene índice = 3 y el valor = 7, lo que significa que el valor del parámetro 3 (“ d ”) inicialmente aparece en pares no utilizados 7: (a, d), (b, d), (d, g), (d, h), (d,), (d, j) y (d, k). El objeto testSets contiene los resultados de conjunto de prueba en pares. Inicialmente está vacío, pero crece cada vez que se genera un nuevo conjunto de pruebas. Cada conjunto de pruebas está representada por una matriz int. Así, en la figura 2, la primera prueba establecida en el resultado es {“ un ”, “ c ”, “ g ”, “ j ”}, que está almacenado en la lista de testSets como una matriz con los valores {0,2,6,9}.
Con las estructuras de datos clave en su lugar, QICT lee el archivo de entrada para determinar los valores para numberParameters y numberParameterValues y llenar las matrices legalValues y parameterValues. Uso el enfoque de relativamente vulgar de realizar una lectura inicial del archivo, al restablecer el puntero de archivo y realizar un segundo paso a través del archivo. Una vez legalValues se llena, puedo digitalizar a través de ella para determinar el número de pares de la entrada:
for (int i = 0; i <= legalValues.Length - 2; ++i) {
for (int j = i + 1; j <= legalValues.Length - 1; ++j) {
numberPairs += (legalValues[i].Length * legalValues[j].Length);
}
}
Console.WriteLine("\nThere are " + numberPairs + " pairs ");
Después de la inicialización, la primera fila de legalValues contiene {0,1} y la segunda fila contiene {2,3,4,5}. Observe que los pares determinan por estas dos filas son (0,2), (0,3), (0,4), (0,5), (1,2), (1,3), (1,4) y (1,5), y que en general, el número de pares determinado por dos filas en legalValues es el producto del número de valores de las dos filas, que es igual a la propiedad de longitud de las filas de la fila. La siguiente parte de QICT código rellena la lista de unusedPairs:
unusedPairs = new List<int[]>();
for (int i = 0; i <= legalValues.Length - 2; ++i) {
for (int j = i + 1; j <= legalValues.Length - 1; ++j) {
int[] firstRow = legalValues[i];
int[] secondRow = legalValues[j];
for (int x = 0; x < firstRow.Length; ++x) {
for (int y = 0; y < secondRow.Length; ++y) {
int[] aPair = new int[2];
aPair[0] = firstRow[x];
aPair[1] = secondRow[y];
unusedPairs.Add(aPair);
}
}
}
}
Aquí tomar cada par de filas de legalValues utilizando indiza i y j. A continuación, guiaré a través de los valores de cada par de fila mediante índices x e y. Un uso extensivo de varios anidada bucles for como éste es un distintivo del código combinatorio. Cuando escribo dicho código, siempre dibujar a mano en un trozo de papel las matrices complejo porque es bastante fácil cometer errores sin un diagrama. Tras rellenar la lista de unusedPairs, uso la misma estructura de bucle anidado para llenar las matrices allPairsDisplay y unusedPairsSearch. A continuación, el código de inicialización llenará la matriz de parameterPositions recorriendo en iteración legalValues:
parameterPositions = new int[numberParameterValues];
int k = 0;
for (int i = 0; i < legalValues.Length; ++i) {
int[] curr = legalValues[i];
for (int j = 0; j < curr.Length; ++j) {
parameterPositions[k++] = i;
}
}
El código de inicialización concluye rellenando la matriz unusedCounts:
unusedCounts = new int[numberParameterValues];
for (int i = 0; i < allPairsDisplay.GetLength(0); ++i) {
++unusedCounts[allPairsDisplay[i, 0]];
++unusedCounts[allPairsDisplay[i, 1]];
}
Aquí, como en muchas de las rutinas QICT, aprovechar el hecho de que C# inicializa automáticamente todas las celdas en matrices de int a 0. Si desea adaptada QICT a un estilo orientado a objetos, todas estas rutinas de inicialización es probable que mejor se colocarían en un constructor de objetos o quizás en un método Initialize() explícito. Comienza el bucle de procesamiento principal:
testSets = new List<int[]>();
while (unusedPairs.Count > 0) {
int[][] candidateSets = new int[poolSize][];
for (int candidate = 0; candidate < poolSize; ++candidate) {
int[] testSet = new int[numberParameters];
// fill candidate testSets
}
// copy best testSet into testSets collection; upate data structues
}
Porque se conoce el número de conjuntos de prueba de candidato a ser poolSize, I puede crear una instancia de una matriz en lugar de utilizar un objeto de lista dinámicos de tamaño. Observe que el tamaño de la colección unusedPairs controla la salida de bucle de procesamiento principal. Ahora es el momento de elegir el par “ mejor ” no utilizado, y ahora iniciar cosas para convertirse en realmente interesantes:
int bestWeight = 0;
int indexOfBestPair = 0;
for (int i = 0; i < unusedPairs.Count; ++i) {
int[] curr = unusedPairs[i];
int weight = unusedCounts[curr[0]] + unusedCounts[curr[1]];
if (weight > bestWeight) {
bestWeight = weight;
indexOfBestPair = i;
}
}
Aquí defino mejor para significar el par no utilizado que tiene la suma de más alta de valores de parámetro individuales no utilizados. Por ejemplo, si “ un ” aparece una vez en la lista actual de pares no utilizados, “ b ” aparece dos veces, tres veces y “ d ” ” c “ cuatro veces, a continuación, par (a, c) tiene peso 1 + 3 = 4, y par (b, d) tiene peso (b, d) 2 + 4 = 6, por lo que se seleccionarían par (b, d) a través de (a, c).
Hay muchos otros esquemas de ponderación que desea explorar. Por ejemplo, con algún tipo de multiplicación ofrecería mayor pesos a pares con valores extremos de recuentos no utilizados en comparación con pares no utilizado que tienen cuenta más cerca juntos. Otra posibilidad es hacer el seguimiento de recuentos utilizados: el número de veces aparecen valores de parámetro en los conjuntos de prueba ya agregados a la colección de testSets resultados — y picking como uno que tiene los recuentos utilizados menos emparejar el mejor. Una vez determinado el mejor par no utilizado, se crea una matriz de dos celdas para contener los valores del par y determinar las posiciones dentro de un conjunto de pruebas que pertenece cada valor:
int[] best = new int[2];
unusedPairs[indexOfBestPair].CopyTo(best, 0);
int firstPos = parameterPositions[best[0]];
int secondPos = parameterPositions[best[1]];
En este punto tengo un conjunto de prueba vacía y un par de valores para colocar en el conjunto de pruebas y sé que la ubicación dentro del conjunto de pruebas que pertenecen los valores. El paso siguiente es generar valores de parámetro para las restantes posiciones en el conjunto de pruebas. Ahora, en lugar de rellenar las posiciones de conjunto de pruebas en algún orden fijo (desde el índice baja a alta), resulta que es mucho mejor rellenar el conjunto en orden aleatorio de prueba. En primer lugar, puedo generar una matriz que contiene las posiciones de parámetro en orden secuencial:
int[] ordering = new int[numberParameters];
for (int i = 0; i < numberParameters; ++i)
ordering[i] = i;
A continuación, reorganizar el orden colocando las ubicaciones de los dos primeros valores del par de mejor conocidas en las dos primeras celdas de la matriz de ordenación:
ordering[0] = firstPos;
ordering[firstPos] = 0;
int t = ordering[1];
ordering[1] = secondPos;
ordering[secondPos] = t;
Y ahora mezclar las restantes posiciones (desde la celda 2 y copia) mediante el algoritmo de orden aleatorio Knuth. Ésta es la razón por la que se ha creado un objeto Random al principio del código QICT. El número de conjuntos de prueba generado por QICT es sorprendentemente confidencial en el valor del pseudoaleatorios número generador valor de inicialización, por lo que quizás desee experimentar con varios valores de inicialización. Para la situación con 20, los parámetros de valor 10 que describí anteriormente, utilizando un valor de inicialización el valor de 2 genera 219 conjuntos de prueba y un valor de inicialización de 6 genera 216 conjuntos de prueba, pero un valor de inicialización 0 produce 221 conjuntos de prueba.
for (int i = 2; i < ordering.Length; i++) {
int j = r.Next(i, ordering.Length);
int temp = ordering[j];
ordering[j] = ordering[i];
ordering[i] = temp;
}
Después de barajando, coloco los dos valores del par de mejor en el conjunto de prueba del candidato:
testSet[firstPos] = best[0];
testSet[secondPos] = best[1];
Ahora viene la parte más importante del algoritmo QICT. Puedo debo determinar los valores de parámetro mejores colocar en cada una de las posiciones de conjunto de pruebas vacías. La técnica que utilizo es otro enfoque ávido. Para cada posición de parámetro, se prueba cada valor posible legal en esa posición, contando cuántos pares no utilizados en el valor de prueba, cuando se combina con los otros valores ya en la prueba establecen captura. A continuación, seleccionar el valor del parámetro que captura a los pares de no más utilizados. El código para ello es la parte más complicada de QICT y aparece en de figura 4.
Figura 4 de Filling Test Set con valores de parámetro Best
for (int i = 2; i < numberParameters; ++i) {
int currPos = ordering[i];
int[] possibleValues = legalValues[currPos];
int currentCount = 0;
int highestCount = 0;
int bestJ = 0;
for (int j = 0; j < possibleValues.Length; ++j) {
currentCount = 0;
for (int p = 0; p < i; ++p) {
int[] candidatePair = new int[] { possibleValues[j],
testSet[ordering[p]] };
if (unusedPairsSearch[candidatePair[0], candidatePair[1]] == 1 ||
unusedPairsSearch[candidatePair[1], candidatePair[0]] == 1)
++currentCount;
}
if (currentCount > highestCount) {
highestCount = currentCount;
bestJ = j;
}
}
testSet[currPos] = possibleValues[bestJ];
}
El bucle más externo en de figura 4 es un recuento del número total de prueba conjunto posiciones (dada por numberParameters), menos de dos (porque se utilizan dos zonas por el par mejor). Dentro del bucle recuperar la posición de la zona actual para rellenar mirando en la matriz de ordenación que se ha creado anteriormente. La variable currentCount contiene el número de pares no utilizados capturados por el valor del parámetro de prueba. Observe que ya estoy rellenar las posiciones de conjunto de pruebas en orden aleatorio, el par de candidatos de valores puede fuera de uso, así que necesito comprobar dos posibilidades al realizar la búsqueda en la matriz unusedPairsSearch. Al final del código de de figura 4, tendrá un candidato conjunto que tiene valores de cada posición que se seleccionaron mediante algoritmos avariciosos de pruebas. Ahora simplemente agregar esta prueba candidato establecido en la colección de candidatos:
candidateSets[candidate] = testSet;
En este punto tengo n = poolSize candidato prueba conjuntos y se debe seleccionar el mejor estos a agregar a la colección de resultados principal testSet. Podría Asumo que el primer conjunto de candidatos prueba captura a los pares de no más utilizados y simplemente recorrer en iteración cada candidato comenzando en la posición 0, pero de nuevo, introducción a algunos aleatoriedad produce mejores resultados. Elegir una zona aleatoria dentro de los candidatos y suponer que éste es el mejor candidato:
int indexOfBestCandidate = r.Next(candidateSets.Length);
int mostPairsCaptured =
NumberPairsCaptured(candidateSets[indexOfBestCandidate],
unusedPairsSearch);
Aquí uso una pequeña función auxiliar denominada NumberPairsCaptured() para determinar cuántos pares no utilizados se capturan por un conjunto de prueba determinada. La función auxiliar es:
static int NumberPairsCaptured(int[] ts, int[,] unusedPairsSearch)
{
int ans = 0;
for (int i = 0; i <= ts.Length - 2; ++i) {
for (int j = i + 1; j <= ts.Length - 1; ++j) {
if (unusedPairsSearch[ts[i], ts[j]] == 1)
++ans;
}
}
return ans;
}
Ahora guiaré a través de cada conjunto de pruebas candidato, seguimiento de la ubicación de la uno que captura a los pares de no más utilizados:
for (int i = 0; i < candidateSets.Length; ++i) {
int pairsCaptured = NumberPairsCaptured(candidateSets[i],
unusedPairsSearch);
if (pairsCaptured > mostPairsCaptured) {
mostPairsCaptured = pairsCaptured;
indexOfBestCandidate = i;
}
}
Y ahora copiar la mejor prueba candidato establecido en el objeto de lista de testSets de resultado principal:
int[] bestTestSet = new int[numberParameters];
candidateSets[indexOfBestCandidate].CopyTo(bestTestSet, 0);
testSets.Add(bestTestSet);
En este punto, he genera y agrega un nuevo conjunto de prueba, por lo que debo actualizar todas las estructuras de datos que se ven afectadas, es decir, el unusedPairs lista (quitando todos los pares generados por el nuevo conjunto de pruebas), la matriz unusedCounts (por disminuir el recuento para cada valor de parámetro en el nuevo conjunto de pruebas) y la matriz unusedPairsSearch (por voltear los valores asociados con cada par generadas por la nueva prueba establecer entre 1 y 0).
Ahora estoy al final de mi bucle de procesamiento principal. Continuar generando a candidatos, selección del mejor candidato, la adición del mejor candidato para testSets y las operaciones de estructuras de datos de actualización. El procesamiento finalizará cuando llegue a 0 el número de pares no utilizados.
A continuación, mostrar los resultados finales:
Console.WriteLine("\nResult testsets: \n");
for (int i = 0; i < testSets.Count; ++i) {
Console.Write(i.ToString().PadLeft(3) + ": ");
int[] curr = testSets[i];
for (int j = 0; j < numberParameters; ++j) {
Console.Write(parameterValues[curr[j]] + " ");
}
Console.WriteLine("");
}
Console.WriteLine("");
}
Como mencioné anteriormente, si está modificando QICT para adaptarse a su propio escenario concreto de pruebas, puede que desee emitir resultados directamente a un archivo XML, una base de datos SQL o alguna otra forma de almacenamiento.
Producir mejores Systems
Pruebas desunidas par a par son una técnica combinatorio con factores probabilística. Generación de prueba en pares establecido es una técnica importante, pero no es mágica. Recuerde que las técnicas en pares simplemente reducen el número de entradas del caso de prueba en situaciones donde tiene demasiados casos de prueba para tratar con sólo. Generación de prueba en pares establecido no crea los resultados esperados de caso de prueba. Debe siempre empezar por utilizar los principios de pruebas normales, como sucede con las condiciones de límite, mediante entrada aleatorio puro y así sucesivamente y, a continuación, utilice desunidas par a par pruebas para complementar la generación de caso de prueba. Además, como regla general, son mejor, más pruebas, por lo que no hay ninguna razón por qué no se puede agregar entradas de caso de prueba adicionales a los producidos por las herramientas de generación en pares. Aunque son útil en muchas situaciones en las pruebas desunidas par a par, asegúrese de utilizarla sólo cuando sea apropiado.
He encontrado prueba en pares generación establecido a ser muy útil para las pruebas de configuración, para módulo probar métodos que aceptan valores enumerados y para pruebas de las bases de datos SQL donde cada columna de una tabla tiene un número relativamente pequeño de valores diferentes. Pruebas desunidas par a par no son necesariamente un buen enfoque para escenarios donde tenga un número relativamente pequeño de entradas del caso de prueba, o cuando mediante programación producir resultados de prueba-caso esperado (y, por tanto, tratar con un gran conjunto de entrada de caso de prueba). Y pruebas desunidas par a par no son utilizable normalmente cuando los valores de entrada para el sistema de prueba no son discretos. Sin embargo, incluso en situaciones donde el número de valores posibles del parámetro es muy grande, es posible que pueda utilizar eficazmente el caso de prueba en pares generación de entrada, separando los valores de parámetro en las clases de equivalencia. Cuando se utiliza correctamente, desunidas par a par establecido la generación de pruebas es una técnica importante que le puede ayudar a producir mejor los sistemas de software.
Dr.James McCaffrey funciona en Volt Information Sciences Inc., donde encarga de formación técnica para los ingenieros de software basado en Redmond, Washington, campus. de Microsoft Ha trabajado en varios productos de Microsoft, incluidos Internet Explorer y MSN Search y es autor de .NET prueba Automation Recipes: Enfoque de solución de problemas(Apress, 2006). James puede ponerse en jmccaffrey@volt.com de o v-jammc@microsoft.com.
Gracias al siguiente técnico experto para revisar este artículo: Jacek Czerwonka
Envíe sus preguntas y comentarios para James a testrun@microsoft.com de.