Compartir a través de


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

SQL Server

Pruebas unitarias para cubos de OLAP con SQL Server en C#

Mark Nadelson

Descargar el código de ejemplo

Me siento un poco como Thomas Jefferson cuando digo, "sostenemos que estas verdades son evidentes, que todo el código que tiene ciertos derechos inalienables y que entre estos derechos es la capacidad de ser completamente unidad probada en una manera simple y concisa para insectos pueden ser fácilmente identificados y las interrupciones de producción minimizadas." Un poco dramático, sí, pero es mi punto a través de.

Por supuesto, la mayoría de los desarrolladores creen su código debe ser unidad probada, pero ¿qué sucede cuando la definición de «código» es borrosa? Esta era la situación encontré en recientemente cuando se presentó con un tema complicado y la tarea de encontrar una solución. Un grupo de desarrolladores estuvo involucrado con la escritura un cubo complejo procesamiento analítico en línea (OLAP) mediante servicios de análisis de SQL Server (SSA). Este cubo tenía numerosas dimensiones todo atados a una tabla de hechos extremadamente complejo. Porque los desarrolladores eran muy hábiles en el desarrollo de cubos, fueron capaces de armar el cubo, sino validar los resultados de sus consultas de expresiones multidimensionales (MDX) era una tarea titánica. La dificultad fue agravada por una serie de factores, incluyendo la cantidad de datos en la tabla de hechos y las dimensiones, así como el tiempo y los recursos necesarios para construir el cubo de la computación. Una vez construido el cubo, los resultados (producidos por consultas MDX) fueron enviados a los usuarios. Si no encuentran un problema con los datos de los usuarios, tardaría mucho tiempo para localizar el problema. Además, una vez que el problema subyacente fue descubierto y corregido, el cubo necesitaría ser regenerado. Para colmo de males, si dimensiones fueron agregados, se actualizó la tabla subyacente o el cubo fue construido utilizando diferentes agregaciones, no había ninguna manera de determinar los efectos de estos cambios. Un cambio aparentemente inocente podría tener un efecto en cascada y de largo alcance en las consultas al cubo.

La solución para el enigma de cubo es crear un entorno y un proceso en el cual puede etapa dimensiones del cubo y hechos usando una cantidad limitada de datos y ejecutar consultas contra el cubo utilizando la versión de producción del esquema del cubo. Idealmente la versión de prueba del cubo se crearían desde cero cada vez que ejecutan las pruebas unitarias, eliminando la posibilidad de efectos secundarios que ocurren de los artefactos existentes. Otros requisitos para el framework de pruebas unitarias (y realmente esto se aplica a la mayoría de los entornos de pruebas unitarias independientemente de la aplicación de destino) para garantizar las validaciones de prueba son repetibles y si se presenta insuficiencia de forma rápida y fácil determinar por qué la prueba falló (teniendo el caso prueba decir "falló porque no concordaban con datos" no es lo ideal).

En este artículo, se presento un marco que le permite crear un conjunto de pruebas unitarias para validar la salida de un cubo OLAP basado en MDX. Se describe la arquitectura permite la creación de un cubo mediante un esquema existente, dentro de su propia base de datos de pruebas unitarias, recreado cada vez que se ejecuta el paquete de pruebas. También le permite proporcionar consultas MDX que se ejecutan en la versión de prueba de unidad recién formado del cubo. Además, valida los resultados contra una plantilla preexistente y los presenta en formato HTML simple. Este patrón de prueba de validación contra una plantilla puede extenderse a los marcos de pruebas unitarias en el cual los resultados de datos son grandes y complejos.

Resumen de cubo

Antes de adentrarse en la solución para el tema prueba de cubo, voy a salir brevemente sobre los conceptos y componentes que conforman un cubo. Los cubos son un medio de acceder rápidamente a datos dentro de un almacén de datos. Cubos de organizan y resumen los datos en una estructura multidimensional. Los cubos son el principal componente de la tecnología OLAP y proporcionan un mecanismo fácil de usar para consultar datos con tiempos de respuesta rápidos y predecibles. Un cubo se compone de los datos de la dimensión y medidas (datos numéricos). La tabla central de un cubo es conocida como la tabla de hechos, y es la fuente de las medidas del cubo. La tabla hace referencia a las tablas de dimensiones, y contienen niveles jerárquicos de la información que se puede consultar. La jerarquía de dimensión permite a los usuarios hacer preguntas a un alto nivel. Luego, usando la jerarquía de la dimensión, los usuarios pueden obtener para más detalles.

Cubos están contenidos en una base de datos. Los objetos que conforman la estructura del cubo para una base de datos son los siguientes:

  • Fuentes de datos: Estas son las fuentes de la información a ser cargado en el cubo.
  • Medidas: Estos son los valores numéricos representados en el cubo. Ellos pueden ser las fechas, pero son generalmente numéricos con diferentes niveles de agregación (por ejemplo, suma, Max, Min y Conde).
  • Dimensiones: Estos son atributos asociados con las medidas. Datos de negocio, los nombres de clientes y regiones geográficas son ejemplos comunes de dimensiones.
  • Particiones: Una partición define una porción de los datos de hechos cargados en un grupo de medida. Al crear varias particiones, el cubo puede ser procesado en paralelo y almacenado y preguntó por separado, de tal modo mejorando el rendimiento. Usted también puede reprocesar las particiones individuales sin afectar a otras particiones.
  • Cubo de papel: Cada cubo debe tener al menos una función de cubo para permitir el acceso a los usuarios finales. Roles pueden permitir acceso a todos los datos o a un subconjunto de los datos almacenados dentro del cubo basado en un ID de usuario individual o un grupo de Active Directory.

La definición de esquema de un cubo puede extraerse de la SSA en la forma de XML para análisis (XMLA). XMLA es un protocolo XML basados en SOAP que da acceso al cubo sobre HTTP. La definición de XMLA contiene todos los detalles para cada uno de los objetos de cinco cubo descritos anteriormente. XMLA le permite recrear el cubo en diferentes bases de datos o servidores de forma rápida y sencilla. Es la piedra angular, por el cual se crea el cubo unidad-comprobable.

Una vez que un cubo es creado y procesado, pueden consultar las medidas de datos usando una mezcla y fósforo de la variedad de dimensiones usado para crearlo. Cubos son consultados con la sintaxis MDX antes mencionada. Al igual que una consulta SQL, una consulta MDX contiene una solicitud de datos (mediante la instrucción SELECT), un punto de datos (mediante la instrucción de) y un filtro opcional de datos (mediante la cláusula WHERE). Aquí está un ejemplo básico:

    SELECT {[<axis specification using Measures>]...} ON AXIS(0),
           {[<axis specification using a dimension hierarchy>]...} ON AXIS(1)
    FROM [<cube>]
    WHERE (<filter specification>)

El cubo ventas ejemplo

Creé un cubo de ejemplo que le permite rápidamente datos de ventas de consulta para varios almacenes en varias fechas por diversos clientes (ver figura 1).

Example Sales Cube Database Diagram
Figura 1 diagrama de base de datos ejemplo cubo ventas

El cubo se compone de cuatro tablas de dimensiones conectar a una tabla de hechos. Por razones de simplicidad, la tabla contiene una medida llamada cantidad, que representa la cantidad de un determinado artículo vendido a un cliente determinado en un lugar de tienda en una fecha determinada compra. Con esta configuración de cubo, el usuario puede consultar rápidamente por varios hechos usando diversas dimensiones. Por ejemplo, ejecutivos corporativos pueden obtener una idea clara de que productos se venden en las tiendas que, o puede profundizar en detalles como que vendan mejor durante un año en particular o un mes. Tener un gran número de dimensiones permite un ejecutivo información ventas en una variedad de maneras, proporcionando mejor penetración en el desempeño de las tiendas.

Creación de la versión de pruebas unitarias del cubo

Como se ha mencionado, la definición de cubo puede extraerse de la SSA en la forma de un documento XMLA. Este documento XMLA se utiliza para crear la versión de prueba de unidad del cubo. Usando la definición de producción del cubo asegura que las pruebas con precisión ejercerá todas las funciones del cubo en cuestión. Te la interfaz con el motor SSAS usando Microsoft.AnalysisServices.dll, que pueden encontrarse en las Asambleas de SQL Server SDK.

El objeto utilizado para generar el cubo es XMLAtoCube. El constructor toma en un directorio de configuración de base bajo la cual se almacena el XMLA. La estructura de directorios que elegí para albergar el cubo XMLA es el directorio base de < > \ < nombre del servidor de producción > \­< nombre de base de datos de producción >.

XMLAtoCube contiene un método público, CreateCubeFromXMLA, que tiene los siguientes parámetros (ver código del método en Listado 1 en el archivo Listings.zip en la descarga de código adjunto):

  • SourceServerName: El nombre del servidor de producción que contiene el cubo.
  • TargetServerName: El nombre del servidor que albergará la versión de prueba de unidad del cubo.
  • SourceDatabaseName: El nombre de la base de datos de producción que contiene el cubo.
  • TargetDatabaseName: El nombre de la base de datos que albergará la versión de prueba de unidad del cubo.
  • DataSourceProviderDefinition: La URL de cadena de conexión que señala la versión de prueba de unidad del cubo a la ubicación de sus cotas de origen y la tabla de hechos. Esta será la fuente de los datos de escala para la prueba unitaria.

CreateCubeFromXMLA primero establece una conexión con la versión del servidor de análisis de pruebas unitarias y baja la versión de pruebas unitarias de la base de datos del cubo si ya existe. El lanzamiento de la base de datos es importante porque se asegura que las pruebas se llevan a cabo en un ambiente limpio sin ningún contam artefactos residual­INAR el resultado. La conexión con el servidor de análisis se ejecuta dentro del método ConnectToServer utilizando una instancia de Microsoft.AnalysisServices.Server. Una llamada a Server.Connect (cadena de conexión < >) utilizando el nombre del servidor de pruebas unitarias aprobado en establece la conexión (ver Listado 2 en la descarga de código). Una vez establecida la conexión al servidor con éxito, se elimina la versión de pruebas unitarias de la base de datos del cubo si ya existe. Esta eliminación se realiza con el método DropDatabase, que se pasa la instancia del servidor conectada y el nombre de la base de datos de pruebas unitarias para soltar (TargetServerName). DropDatabase garantiza que la instancia del servidor está conectado, mira hacia arriba la Microsoft.Analysis­Services.Database utilizando el nombre de pruebas unitarias de base de datos aprobada en y, si existe la base de datos (la instancia de base de datos no es nula), la base de datos se ha caído (ver Listado 3 en la descarga de código).

El siguiente paso es tomar la definición del cubo original XMLA y generar la versión de prueba de unidad. La versión de prueba de unidad contiene las mismas dimensiones, jerarquías de dimensión, medidas, particiones, papeles y así sucesivamente como el cubo original. La diferencia es que se genera en una nueva base de datos apuntando a una ubicación diferente para su origen de datos. El método AddCubeToDatabase crea el cubo de prueba (ver Listado 4 en la descarga de código). AddCubeToDatabase Lee la definición de XMLA desde el sistema de archivos utilizando la Convención de nomenclatura mencionada anteriormente. El nombre del archivo XMLA se pasa a una instancia de XmlTextReader en construcción. El XMLA es leída en el método Microsoft.AnalysisServices.Utils.Deserialize, que se pasa el XmlTextReader y una instancia de Microsoft.AnalysisServices.Database recién creada. La instancia de objeto de base de datos contiene la definición completa del cubo, pero esa definición todavía tiene fuente de nombre y datos de base de datos del cubo original. Simplemente apuntando a la pruebas unitarias de base de datos consiste en establecer las propiedades Name y el ID de la "base de datos a nombre de la base de datos de pruebas unitarias" parámetro (targetDatabaseName). Esta base de datos entonces puede agregarse a la instancia del servidor de análisis de pruebas unitarias llamando al Server.Databases.Add (base de la prueba de unidad < >) seguido por el método Database.Update.

Después de que se ha creado la base de datos, necesitas actualizar el origen de datos del cubo a la colección de datos de prueba de unidad externa. La instancia de base de datos tiene una lista de instancias de origen de datos (generalmente un origen de datos está asociado con un cubo) y la cadena de conexión de pruebas unitarias se utiliza para reemplazar la cadena de conexión contenida dentro de la definición de XMLA. Después se sustituye la cadena de conexión, una llamada al método DataSource.Update actualiza dentro del servidor SSAS. En este punto, se completa la personalización de la definición de XMLA y las partes restantes del cubo (DataSourceView, dimensión y cubo) son actualizadas y procesadas.

Una vez finalizada la llamada a AddCubeToDatabase, la versión de prueba de unidad del cubo se ha creado dentro del servidor especificado utilizando la base de datos de las pruebas unitarias. Apunta a un conjunto personalizado de origen de datos. Aunque se ha creado el cubo, es vacío. Para poblar las dimensiones con los datos de origen, las dimensiones deben ser procesadas. El método ProcessDimensions se llama y pasaron a la instancia de base de datos. Todas las dimensiones dentro de la base de datos se procesan utilizando el método Dimension.Process(ProcessType.ProcessFull). Una vez que han sido procesadas con éxito las dimensiones, los cubos de las pruebas unitarias de base de datos se procesan utilizando el método ProcessCube. Como ProcessDimensions, ProcessCube toma la instancia de base de datos, recorre todos los cubos en la base de datos y llama a Cube.Process(ProcessType.ProcessFull) (ver Listado 5 en la descarga de código). En este punto, el cubo de pruebas unitarias ha creado y rellena con los datos de prueba específicos. El siguiente paso es hacer pruebas contra él para asegurarse de que el cubo se comporta como se esperaba.

Validar el cubo

Aunque la solución para la validación está dirigida para el cubo, el patrón de diseño se utiliza puede aplicar a otros marcos de pruebas unitarias así. El patrón empleado está poniendo a prueba usando validación de plantilla. En pocas palabras: Cuando se ejecuta la prueba, una estructura de datos que contiene el resultado es creada y validada contra una versión almacenada con anterioridad de la estructura de datos que se consideraba correcta. Porque es difícil de validar una estructura de datos binarios, se presenta una representación HTML de la estructura para el probador de la unidad. El probador usa la representación HTML para validar los resultados de la prueba inicial de la prueba unitaria (para asegurarse de que los resultados coinciden con lo que se espera) y examinar lo que causó una prueba unitaria a fracasar durante ejecuciones posteriores. En un fallo, el código HTML muestra la estructura de datos original como así como que el dato estructura falló validación y por qué. Esto es fundamental para ayudar a depurar el problema.

La mejor manera de probar la mayoría de los escenarios está utilizando la metodología de prueba de "caja negra". Una prueba de caja negra pasa de entrada y salida valida. Debido a la salida de un cubo es un resultado de la consulta, la entrada es la consulta. Utilice las declaraciones de MDX para consultar un cubo. Después de que el cubo interpreta la consulta MDX, devuelve un resultado. El resultado es en forma de filas y columnas que son una representación de las dimensiones elegido para ejecutar la consulta MDX. Resultado de la consulta MDX puede ser bastante complejo porque la consulta puede implicar muchas dimensiones, resultando en una variedad de filas y columnas en la salida. Los datos de la estructura elegida para mantener que los datos del cubo están un diccionario de instancias de CubeRow introducido por el nombre de la fila del cubo. La clase CubeRow contiene dos estructuras de datos alternativo — el que se usa depende de la situación. Una estructura de datos es un diccionario de instancias de CubeTuple introducido por el nombre de la columna del cubo. La CubeTuple es simplemente un objeto que contiene el nombre de columna del cubo y dado valor de la columna. Los Diccionario de CubeTuble objetos se utiliza cuando la columna dada cubo contiene un valor. La segunda estructura de datos es otro diccionario, asignación de un nombre de la fila a una instancia de CubeRow. Debido a una consulta MDX puede tener muchos niveles de dimensiones de fila, CubeRow contiene su propio diccionario de nombre de la fila y las instancias de CubeRow.

No sólo son los resultados del cubo almacenados en un diccionario < String, CubeRow > instancia, los resultados también se almacenan en una cadena HTML. La cadena HTML permite el probador tener una representación visual de los resultados del cubo. La tabla HTML contiene múltiples niveles de encabezados de columna y fila, y las celdas de una tabla HTML contienen los valores MDX. Figura 2 muestra la disposición de la representación HTML de un resultado de la consulta MDX.

Figura 2 el diseño de la representación HTML de un resultado de la consulta MDX

   

Dimensión de la columna

Título 1 (valor 1)

Dimensión de la columna

Título 1 (valor 1)

Dimensión de la columna

Título 1 (valor 2)

Dimensión de la columna

Título 1 (valor 2)

   

Dimensión de la columna

Título 2 (valor 1)

Dimensión de la columna

Título 2 (valor 2)

Dimensión de la columna

Título 2 (valor 1)

Dimensión de la columna

Título 2 (valor 2)

Dimensión de fila

Título 1 (valor 1)

Dimensión de fila

Título 2 (valor 1)

Valor del resultado MDX Valor del resultado MDX Valor del resultado MDX Valor del resultado MDX

Dimensión de fila

Título 1 (valor 1)

Dimensión de fila

Título 2 (valor 2)

Valor del resultado MDX Valor del resultado MDX Valor del resultado MDX Valor del resultado MDX

Dimensión de fila

Título 1 (valor 2)

Dimensión de fila

Título 2 (valor 1)

Valor del resultado MDX Valor del resultado MDX Valor del resultado MDX Valor del resultado MDX

Dimensión de fila

Título 1 (valor 2)

Dimensión de fila

Título 2 (valor 2)

Valor del resultado MDX Valor del resultado MDX Valor del resultado MDX Valor del resultado MDX

BaseMDXTest contiene el código para ejecutar una consulta MDX y construcción de la estructura de datos del resultado MDX, así como el representante XML. BaseMDXTest utiliza Microsoft.Analysis­Services.AdomdClient.dll, encontrado en las asambleas SQL Server SDK, para conectar con el cubo SSAS y ejecutar las consultas MDX. BuildTemplate es el método que se ejecuta la consulta MDX y construye el MDX resultado diccionario, así como la representación de HTML. En primer lugar, se establece una conexión con el cubo. Con el fin de establecer y abrir una conexión, la cadena de conexión se pasa a una instancia de MicrosoftAnalysisServices.AdomdClient.AdomdConnection. Luego se llama al método Open de la instancia recién creada conexión y se devuelve la instancia de conexión al llamador. Una vez que se crea una conexión, una instancia de la MicrosoftAnalysis­Services.AdomdClient.AdomdCommand método se establece y se pasa la cadena de consulta MDX y la instancia de AdomdConnection. Una llamada al método AdomdCommand.ExecuteCellSet se ejecuta la consulta MDX contra la versión de prueba de unidad del cubo y devuelve una instancia de MicrosoftAnalysisServices.AdomdClient.CellSet (ver listado 6 en la descarga de código).

Después de que la instancia del conjunto de celdas se recupera, es hacer una revisión para asegurar que el conjunto de resultados tiene dos ejes. Eje 0 contiene las columnas y las filas eje 1. Cada eje contiene una colección de objetos de posición. Una posición representa una tupla en el eje determinado y contiene uno o más objetos de miembro. Un miembro representa los encabezados de columna o fila para la posición dada (ver listado 7 en la descarga de código).

A continuación, se calcula el número de filas y columnas devueltas por la consulta MDX. Esto se realiza tomando el número de filas (el recuento de objetos de posición en el eje 1) más el número de dimensiones de la columna (CellSet.Axes[0].Posiciones [0].Members.Count). El número de columnas se agrega a las filas porque al representar los resultados MDX como una tabla de dos dimensiones, las columnas están incluidas dentro del conjunto de filas. Asimismo, el número de columnas se calcula tomando el número de posición de objetos en eje 0 más el número de dimensiones de fila (ver listado 8 en la descarga de código).

Dado el número de filas y columnas, se pueden generar los objetos Diccionario de CubeRow así como la representación HTML de la salida MDX. Listado 9 en el código de descarga contiene el código para atravesar el resutado MDX, creando el código HTML y guardar los resultados en el diccionario CubeRow. En primer lugar, el número de filas se enlaza a través. Si el número de fila es mayor que el número de dimensiones de la columna, entonces se sabe que una nueva fila de resultados MDX está disponible. En otras palabras, cuando han pasado las filas de encabezados de columna, los datos MDX están disponibles. En este punto, se crea un nuevo objeto CubeRow.

El siguiente paso es recorrer cada columna dentro de la fila. Si el número de fila actual es menor que el número de dimensiones de la columna, entonces la fila actual es en realidad una fila de encabezados de columna. Para el diccionario, los títulos de cabecera se concatenan para cada ubicación de columna, separado por un coma. Esto significa que si un encabezado está compuesto de múltiples dimensiones, cada columna se concatenan con la dimensión dada en orden decreciente de resolución. La generación de HTML para un encabezado de columna es más sencilla. La leyenda de dimensión simplemente está rodeada por las etiquetas de encabezado de tabla HTML (< th >< /th >). Para cada caso, el título actual de dimensión es obtenido por conseguir la cabecera eje (CellSet.Axis[0]) y acceder a la posición de la columna (columna recuento actual menos el recuento actual de la dimensión de fila) y el miembro actual dentro de esa posición (actual recuento de filas).

Si el número de fila actual es mayor que el número de dimensiones de la columna, entonces los encabezados de columna ya no está siendo procesado. En cambio, el resultado MDX define fila tuplas están ahora en línea para el procesamiento. Similar a las columnas, que tienen cabeceras, MDX resultado conjunto filas también pueden tener encabezados. Si el número de columna está procesando es menor que el número de dimensiones de la fila, un encabezado de fila se está tramitando. Para cada encabezado de fila, un nuevo diccionario < cadena, CubeRow > se crea, agrega al diccionario actual y como el resultado MDX actual diccionario. Esto significa que para cada encabezado de fila, existe un diccionario de filas que contiene más datos del resultado granuladas de MDX.

Extrayendo el título de encabezado de fila es similar al extraer el título de encabezado de columna. El título de fila se recupera desde el objeto miembro en la ubicación actual de la columna desde la posición de la fila actual de CellSet.Axis[1]. El título de la fila es la clave para el diccionario de CubeRows, y si el actual Diccionario de CubeRow no tiene el título de la fila extraída, el objeto CubeRow se agrega al diccionario afinado por el título de la fila. Si existe la leyenda de la fila dentro de la actual Diccionario de CubeRow, el objeto CubeRow es obtenido y establece como currentCubeRow.

Después de la fila caption miembros han agotado (es decir, la cuenta actual de columna es mayor que el número de dimensiones de fila) y han sido atravesadas las filas de encabezado de columna (es decir, el recuento de filas actual es mayor que el número de dimensiones de la columna), es hora de agregar los valores de celda MDX al objeto CubeRow actual. Cada combinación de un encabezado de columna y valor de la columna se considera que forman una única instancia de CubeTuple. Cada CubeRow contiene un diccionario de objetos CubeTuple introducido por el encabezado de columna. El encabezado de columna es obtenido de un conjunto de encabezados de columna previamente construidos (recordar un encabezado de columna es un colon -­delimitado por cadena de títulos de columna todos concatenado juntos). El índice del encabezado de la columna es el número de columna actual menos el número de dimensiones de la fila (el Conde de columna total incluye las dimensiones de la fila). El valor actual del conjunto de celdas MDX es obtenido mediante el acceso a los apropiados bidimensional (columna, fila) punto. Esto se basa en el recuento actual de columna (menos el número de dimensiones de fila) y el recuento de filas actual (menos el número de dimensiones de la columna). Este valor se agrega al objeto CubeRow, utilizando el método AddTuple, pasando el encabezado de columna y valor de la columna. Al mismo tiempo, se actualiza la representación HTML agregando el valor de la celda MDX entre fichas HTML tabla Dimensión (< td >< /td >). Ver figura 3 para una representación gráfica del diccionario cadena < CubeRow >.

Representación el diccionario y el HTML de la plantilla se conservan a una ubicación de archivo definido anteriormente utilizando el método BaseMDXTest.PersistTemplate. Ya que la plantilla necesita validarse manualmente por el desarrollador de pruebas unitarias, la prueba se considera que han fallado, que es por el método BaseMDXTest.TestMDXQuery devuelve false para el éxito.

A Graphical Representation of the CubeRow Dictionary
Figura 3 representación gráfica del diccionario CubeRow

Una vez que se ha creado la plantilla, posterior funciona de la misma prueba se valida con la plantilla almacenada con anterioridad. Cuando se llama al método TestMDXQuery, primero es hacer una revisión para ver si existe una prueba con el nombre dado. Si lo hace y no solicitó una nueva creación de plantilla (solicitando a recrear la plantilla puede ocurrir si la plantilla actual es incorrecta), entonces la plantilla de resultado de prueba está cargada en la memoria. La plantilla incluye tanto la representación del objeto y la representación HTML del resutado MDX. El método BaseMDXTest.RunComparison ejecuta la consulta MDX y compara los resultados con la plantilla almacenada. Resultados de la consulta MDX son recorridos de la misma manera como eran durante la creación de plantilla. La principal diferencia entre la creación de la plantilla original y la validación contra la plantilla es que en lugar de crear el diccionario < cadena, CubeRow >, las búsquedas se realizan contra la plantilla de diccionario, comprobar si existen los mismos resultados de consultas MDX. Al bucle a través de las filas y columnas, la tabla HTML se crea la misma manera como durante la creación de la plantilla, excepto que ahora se colorean las células dentro de la tabla HTML. Una celda verde indica que la célula coincide con la plantilla original; un glóbulo rojo muestra un desajuste. Colorear las células y presentarlos en una tabla HTML, el probador de la unidad tiene una visión inmediata de por qué el caso de prueba aprobado o no. Cuando se encuentra un desajuste, un valor booleano (testPass) se establece en false para indicar que el caso de prueba falló.

Mientras atraviesa el MDX consultar resultados y validar contra la plantilla diccionario, cada CubeTuple (un objeto que contiene la dimensión de la columna, nombres concatenados y valor de la columna) encontraron que se ha extraído el actual Diccionario de CubeRow de CubeTuple objetos. Por lo tanto, después de que el resultado de la consulta MDX todo pasa, la plantilla original Diccionario debe tener CubeRow objetos con un vacío objetos Diccionario de CubeTuple si el resultado MDX fue un partido completo. De lo contrario el nuevo resultado de la consulta MDX tenía faltan datos que figuran dentro de los resultados originales. El método BaseMDXTest.CheckForExtraDataInTemplate examina la plantilla Diccionario restante CubeTuple objetos, ejecutando de forma recursiva y devuelve un valor true si CubeTuple los objetos permanecen. El testPass Boolean dentro del método RunComparison está establecida en false si se encuentran datos adicionales, y el caso de prueba de falla.

Después de la MDX resultados han sido totalmente atravesadas y validan la plantilla de diccionario, una instancia del cubo­ComparisonResult objeto es devuelto. Se construye con el testPass Boolean y la tabla HTML mostrando el resultado. El método BaseMDXTest.TestMDXQuery utiliza CubeComparisonResult para construir una página HTML que se muestra la tabla original MDX consulta resultado HTML y la tabla de comparación de HTML. El HTML es persistió en el sistema de archivos mediante la ejecución de una llamada al método BaseMDXTest.PersistTestReport, que crea una página Web Resumen TestReport.html listado de todas las ejecuciones de prueba y enlaces a su HTML resultan páginas, así como un resumen del número de casos de prueba que pasó y no se pudo.

Prueba del cubo de compra

Usando ambos componentes del marco de pruebas de cubo — el código de cubo-creación (XMLAtoCube) y el MDX query plantilla de resultado (BaseMDXTest) — puede crear casos de prueba unitaria que validan el cubo. Aunque el código para el marco es extenso, creando los casos de prueba es simple y sencilla. Listado 10 en el código de descarga contiene muestra pruebas unitarias para la validación del cubo compra. Estos casos de prueba utilizar el Microsoft framework de pruebas, pero puede incorporarse cualquier marco de prueba.

El objeto de pruebas unitarias (PurchaseCubeTest en el ejemplo) hereda de BaseMDXTest. El constructor predeterminado del PurchaseCubeTest construye BaseMDXTest con la URL del servidor SSAS donde se encuentra el cubo y el directorio en el que se guarde la plantilla de resultado de consulta MDX y resultados de las pruebas posteriores.

Un método [TestInitialize] se utiliza para crear la versión de prueba de unidad del cubo compra. Utiliza la definición de XMLA del cubo original y crea en el servidor SSAS pruebas unitarias (targetServerName) mediante una prueba unitaria de base de datos (targetDatabaseName). También señala la fuente datos URL a la ubicación de los datos de dimensión y hecho de prueba. [TestInitialize] se ejecuta una sola vez por un determinado [TestClass], lo que asegura el cubo se crea sólo al principio de la prueba.

Los casos de prueba ellos mismos son métodos anotados ejecutados dentro de [TestMethod]. Cada caso de prueba es simple. La consulta MDX está definida y luego ejecutado utilizando el método BaseMDXTest.TestMDXQuery heredado, nombrar el caso de prueba y pasar la consulta MDX. TestMDXQuery devuelve true si pasa la prueba o false si no lo hace, y se utiliza un método Assert.IsTrue que pasan o no pasan la prueba de unidad. Después de todas las pruebas se han ejecutado, puede abrir el documento resultante de la prueba HTML y los casos de prueba de falla puede ser examinados. Figura 4 contiene un ejemplo de la salida HTML de una de las pruebas.

The HTML Output of an Example Test
Figura 4 la salida HTML de una prueba de ejemplo

Código debidamente probado

Aunque no es sencillo, incluso un cubo OLAP puede ser unidad probada utilizando C#. La inclusión de los Microsoft.AnalysisServices.dll y los archivos Microsoft.AnalysisServicesAdomdClient.dll dentro de las Asambleas de SQL Server proporciona las API para crear y consultar cubos de SSAS. La arquitectura presentada le permite añadir un conjunto de pruebas unitarias que produce salida en un formato legible por fallas en caso de prueba pueden ser identificados rápidamente. El método del caso de prueba de validación por parte de plantilla puede aplicarse a otras arquitecturas de pruebas unitarias donde validación de salida no es sencilla. Ejemplos de estas gama de aplicaciones que dependen de la persistencia de base de datos relacional tradicional donde la plantilla contiene los datos de esperan ser almacenado en la base de datos después de que se ejecuta la aplicación, a las aplicaciones de interfaz de usuario que guarde el estado de la interfaz de usuario en una estructura de datos y Mostrar la interfaz de usuario en un formulario HTML.

No estoy muy seguro si Thomas Jefferson o nuestros padres fundadores compararía las libertades de una nación de los derechos de debidamente probado código, pero estoy casi seguro que sus usuarios y supervisores estaría encantados de saber que su aplicación se ha colocado correctamente a través de sus pasos.

Mark Nadelson es un desarrollador de software profesional con 22 años de experiencia en las industrias de telecomunicaciones, Internet y las finanzas. A lo largo de su carrera ha usado un número de lenguajes de programación incluyendo montaje, C, C++, Java y C#. Nadelson también es autor de dos libros y una serie de artículos técnicos.

Gracias a los siguientes expertos técnicos por su ayuda en la revisión de este artículo: David Neigler (SAC Capital Advisors LP) y Joe Sampino(SAC Capital Advisors LP)
David Neigler es un gestor de desarrollo de la industria de servicios financieros, trabajando en SAC Capital Advisors LP.  Su objetivo es el desarrollo de sistemas de datos grandes problemas que enfrentan las compañías financieras haciendo grandes volúmenes de comercio.

Joe Sampino trabaja en SAC Capital Advisors LP, desarrollo de plataformas de inteligencia de negocios de empresa para los grandes bancos y firmas de inversión.  Crea y administra los almacenes de datos, cubos de Analysis Services SQL Server y sistemas de análisis y reporting de datos por interno, externo, reglamentación y cumplimiento necesita. "