Este artigo foi traduzido por máquina.

SQL Server

Conduzindo testes de unidade de cubos OLAP do SQL Server usando C#

Mark Nadelson

Baixar o código de exemplo

Me sinto um pouco como Thomas Jefferson, quando digo, "nós prendemos estas verdades para ser auto-evidentes, que todos os códigos tem certos direitos inalienáveis e que entre esses direitos é a capacidade de ser completamente a unidade testada de forma simples e concisa para insetos podem ser facilmente identificados e paralisações de produção minimizadas." Um pouco dramático, sim, mas fica meu ponto de vista do outro lado.

Naturalmente, a maioria dos desenvolvedores acreditam que seu código deve ser a unidade testada, mas o que acontece quando a definição de "código" é turva? Esta era a situação, encontrei-me em recentemente, quando apresentado com uma questão complicada e encarregado de encontrar uma solução. Um grupo de desenvolvedores estava envolvido com a gravação de um cubo de complexo de processamento analítico online (OLAP) usando SQL Server Analysis Services (SSAS). Este cubo tinha numerosas dimensões todas amarradas a uma tabela de fatos extremamente complexo. Porque os desenvolvedores estavam bastante hábil em desenvolver cubos, eles foram capazes de juntar as peças do cubo, mas validar os resultados de suas consultas MDX (Multidimensional Expressions) era uma tarefa difícil. A dificuldade foi agravada por uma série de fatores, incluindo a quantidade de dados em dimensões e tabela de fatos, bem como o tempo e os recursos necessários para construir o cubo de computação. Uma vez que o cubo foi construído, os resultados (produzidos por consultas MDX) foram enviados para os usuários. Se os usuários encontraram um problema com os dados, que levaria muito tempo para localizar o problema. Também, uma vez que o problema subjacente foi descoberto e corrigido, o cubo precisa ser regenerado. Para piorar as coisas, se foram adicionadas dimensões, foi atualizada a tabela de fatos subjacentes ou o cubo foi construído usando diferentes agregações, não havia nenhuma maneira de determinar os efeitos dessas mudanças. Uma mudança aparentemente inocente pode ter um efeito de longo alcance e em cascata sobre consultas ao cubo.

A solução para o enigma do cubo é criar um ambiente e um processo no qual você pode fase do cubo, dimensões e fatos usando uma quantidade limitada de dados e executar consultas contra o cubo usando a versão de produção do esquema do cubo. Idealmente a versão de teste do cubo seria criada do zero cada vez que executar os testes de unidade, eliminando a possibilidade de efeitos colaterais ocorrendo de artefatos pré-existentes. Outros requisitos para o framework de teste de unidade (e estes se aplicam à maioria das estruturas de teste de unidade, independentemente da aplicação de destino) para assegurar que as validações de teste são repetidas e se ocorrer falha para rapidamente e facilmente identificar por que o teste falhou (tendo o teste caso dizer que "falhou porque não corresponde a dados" não é o ideal).

Neste artigo, apresentarei um framework que permite que você crie um conjunto de testes de unidade para validar a saída baseada em MDX de um cubo OLAP. A arquitetura descrita permite a criação de um cubo usando um esquema existente, dentro de seu próprio banco de dados de teste de unidade, recriado a cada vez que o suite de teste é executado. Ele também permite que você fornecer consultas MDX que são executadas contra a versão de teste de unidade recém-formada do cubo. Além disso, ele valida os resultados contra um modelo pré-existente e apresenta-los em formato HTML simples. Este padrão de validação de casos de teste contra um modelo pode ser estendido para frameworks de testes de unidade em que os resultados dos dados são grandes e complexas.

Visão geral do cubo

Antes de aprofundar-se a solução para o problema de teste de cubo, vou brevemente sobre os conceitos e componentes que compõem um cubo. Os cubos são um meio de acessar rapidamente os dados mantidos dentro de um armazém de dados. Cubos de organizam e resumam os dados em uma estrutura multidimensional. Os cubos são o principal componente da tecnologia OLAP, e eles fornecem um mecanismo fácil de usar para consultar dados com tempos de resposta rápida e previsível. Um cubo é composto dos dados de dimensão e medidas (fatos numéricos). A tabela central em um cubo é conhecida como a tabela de fatos, e é a fonte das medidas do cubo. As tabelas de dimensão são referenciadas por tabela de fatos, e eles contêm níveis hierárquicos de informação que pode ser consultado. A hierarquia de dimensão permite que os usuários de fazer perguntas de alto nível. Em seguida, usando a hierarquia da dimensão, os usuários podem começ para mais detalhes.

Cubos estão contidos em um banco de dados. Os objetos que compõem a estrutura do cubo para um determinado banco de dados são os seguintes:

  • Fontes de dados: Estas são as fontes da informação a ser carregado para o cubo.
  • Medidas: Estes são os valores numéricos representados no cubo. Eles podem ser datas, mas são geralmente numéricos com diferentes níveis de agregação (por exemplo, Sum, Max, Min e Count).
  • Dimensões: Estes são os atributos associados com medidas. Dados comerciais, nomes de clientes e regiões geográficas são exemplos comuns de dimensões.
  • Partições: Uma partição define uma parte dos dados de fato carregados em um grupo de medidas. Através da criação de várias partições, o cubo pode ser processado em paralelo e armazenados e consultados separadamente, assim, melhorar o desempenho. Você também pode reprocessar as partições individuais, sem afetar as outras partições.
  • Funções de cubo: Cada cubo deve ter pelo menos um papel de cubo para permitir o acesso aos usuários finais. Papéis podem permitir o acesso a todos os dados ou um subconjunto dos dados armazenados dentro do cubo com base em uma ID de usuário individual ou um grupo do Active Directory.

A definição de esquema de um cubo pode ser extraída do SSAS na forma de XML para análise (XMLA). XMLA é um protocolo baseado em SOAP XML que dá acesso ao cubo sobre HTTP. A definição de XMLA contém todos os detalhes para cada um dos cinco cubo objetos descritos anteriormente. XMLA permite recriar o cubo em diferentes bancos de dados ou servidores rapidamente e facilmente. É a pedra fundamental pelo qual o unidade-testável cubo é criado.

Depois que um cubo é criado e processado, as medidas de dados podem ser consultadas usando uma mistura e combinação de uma variedade de dimensões usado para criá-lo. Cubos são consultados com a sintaxe MDX acima mencionada. Como uma consulta SQL, uma consulta MDX contém uma solicitação de dados (usando a instrução SELECT), um ponto de dados (usando a instrução FROM) e um filtro de dados opcional (usando a cláusula WHERE). Aqui está um exemplo básico:

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

O cubo vendas do exemplo

Eu criei um cubo de exemplo que permite que você rapidamente dados de consulta de vendas de várias lojas em vários encontros por vários clientes (ver Figura 1).

Example Sales Cube Database Diagram
Figura 1 diagrama de banco de dados exemplo cubo vendas

O cubo é composto por quatro tabelas de dimensão, conectando-se a uma tabela de fatos. Para manter a simplicidade, a tabela de fato contém uma medida de quantidade, que representa a quantidade de um determinado item vendido a um determinado cliente em um loja local em uma data determinada compra. Com esta configuração do cubo, o usuário pode consultar rapidamente vários fatos usando várias dimensões. Por exemplo, executivos da empresas podem obter uma ideia clara do que estão vendendo produtos em quais lojas, ou eles podem mergulhar em detalhes como quais itens vendem melhores durante um determinado ano ou mês. Ter um grande número de dimensões permite que dados de vendas uma visão executiva em uma variedade de maneiras, fornecendo uma visão melhor para o desempenho das lojas.

Criar a versão de teste de unidade do cubo

Como mencionado, a definição de cubo pode ser extraída do SSAS sob a forma de um documento XMLA. Este documento XMLA é usado para criar a versão de teste de unidade do cubo. Usando a definição de produção do cubo garante que os testes com precisão exercerá todas as características do cubo em questão. Você interface com mecanismo do SSAS usando Microsoft.AnalysisServices.dll, que pode ser encontrado nas assembleias SQL Server SDK.

O objeto usado para gerar o cubo é XMLAtoCube. O construtor aceita um diretório de configuração base sob a qual o XMLA é armazenado. A estrutura de diretórios que eu escolhi para abrigar o cubo XMLA é < diretório base > \ < nome do servidor de produção > \­< nome do banco de dados de produção >.

XMLAtoCube contém um método público, CreateCubeFromXMLA, que usa os seguintes parâmetros (ver código do método em Listagem 1 no arquivo Listings.zip no download do código fornecido):

  • NomeServidorOrigem: O nome do servidor de produção que contém o cubo.
  • TargetServerName: O nome do servidor que vai abrigar a versão de teste de unidade do cubo.
  • SourceDatabaseName: O nome do banco de dados de produção que contém o cubo.
  • TargetDatabaseName: O nome do banco de dados que vai abrigar a versão de teste de unidade do cubo.
  • DataSourceProviderDefinition: A URL de seqüência de caracteres de conexão que aponta a versão de teste de unidade do cubo para a localização de suas dimensões de origem e a tabela de fatos. Esta será a fonte de dados reduzidas para o teste de unidade.

CreateCubeFromXMLA primeiro estabelece uma conexão com a versão do servidor de análise de teste de unidade e descarta a versão de teste de unidade de banco de dados de cubo se ele já existir. A queda do banco de dados é importante porque garante que os testes são realizados em um ambiente limpo, sem qualquer residual artefatos contam­inating o resultado. A conexão com o servidor do analytics é executada dentro do método de ConnectToServer usando uma instância de Microsoft.AnalysisServices.Server. Uma chamada para Server. Connect (< String de conexão >) usando o nome do servidor de teste de unidade passado estabelece a conexão (ver Listagem 2 no download de código). Uma vez que a conexão com o servidor é estabelecida com êxito, a versão de teste de unidade de banco de dados do cubo é removida se ele já existir. Esta remoção é feita com o método de DropDatabase, que é passado a instância de servidor conectada e o nome do banco de dados de teste de unidade para soltar (TargetServerName). DropDatabase garante que a instância de servidor está conectado, olha o Microsoft.Analysis­passado Services.Database usando o nome de banco de dados de teste de unidade e, se existir o banco de dados (a instância de banco de dados não é null), o banco de dados é Descartado (ver Listagem 3 no download de código).

O próximo passo é a definição do XMLA do cubo original e gerar a versão de teste de unidade. A versão de teste de unidade contém as mesmas dimensões, hierarquias de dimensão, medidas, partições, papéis e assim por diante como o cubo original. A diferença é que ele é gerado em um novo banco de dados, apontando para um local diferente para sua fonte de dados. O método AddCubeToDatabase cria o cubo de ensaio (ver listagem 4 no download de código). AddCubeToDatabase lê a definição de XMLA do sistema de arquivos usando a Convenção de nomenclatura mencionada anteriormente. Nome do arquivo o XMLA é passado para uma instância de XmlTextReader em construção. O XMLA é lido usando o método Microsoft.AnalysisServices.Utils.Deserialize, que é passado a XmlTextReader e uma recém-criada instância de Microsoft.AnalysisServices.Database. Agora, a instância do objeto de banco de dados contém a definição completa do cubo, mas essa definição ainda tem a fonte de dados e o nome de banco de dados do cubo original. Apontando para o teste de unidade banco de dados envolve simplesmente definindo as propriedades Name e ID do banco de dados"para o nome de teste de unidade banco de dados" (targetDatabaseName) parâmetro. Este banco de dados pode ser adicionado à instância do servidor de análise de teste de unidade chamando Server.Databases.Add (< unidade de teste dados >), seguido pelo método Update.

Depois foi criado o banco de dados, você precisa atualizar a fonte de dados do cubo para a coleta de dados de teste de unidade externa. A instância de banco de dados tem uma lista de instâncias de fonte de dados (normalmente apenas uma fonte de dados está associada um cubo) e a seqüência de conexão de teste de unidade é utilizada para substituir a seqüência de caracteres de conexão contida dentro da definição de XMLA. Após a seqüência de conexão é substituída, uma chamada ao método Update atualiza-lo dentro do servidor do SSAS. Neste ponto, a personalização de definição de XMLA é concluída e o restante do cubo (DataSourceView, dimensão e cubo) é atualizado e processado.

Após concluir a chamada para AddCubeToDatabase, a versão de teste de unidade do cubo foi criada dentro do servidor especificado, usando o banco de dados de teste de unidade escolhida. Ele aponta para um conjunto personalizado de fonte de dados. Embora o cubo foi criado, é ainda está vazio. Para preencher as dimensões com os dados de origem, as dimensões devem ser processadas. O método ProcessDimensions é chamado e passado a instância de banco de dados. Todas as dimensões do banco de dados são processadas usando o método Dimension.Process(ProcessType.ProcessFull). Uma vez que as dimensões foram processadas com sucesso, os cubos do teste de unidade banco de dados são processados usando o método ProcessCube. Como ProcessDimensions, ProcessCube leva a instância de banco de dados, percorrerá todos os cubos no banco de dados e chama Cube.Process(ProcessType.ProcessFull) (ver listagem 5 no download de código). Neste ponto, o cubo de teste de unidade foi criado e preenchido com os dados de teste de alvo. O próximo passo é executar testes nele para garantir que o cubo se comporta conforme o esperado.

Validando o cubo

Embora a solução para a validação é direcionada para o cubo, o padrão de design sendo usado pode aplicar outros frameworks de testes unitários também. O padrão utilizado é o teste usando a validação do modelo. Basta colocar: Quando o teste é executado, uma estrutura de dados contendo os resultados é criada e validada por comparação com uma versão previamente armazenada de estrutura de dados que foi considerada correta. Porque é difícil validar uma estrutura de dados binários, uma representação de HTML da estrutura é apresentada para o testador de unidade. O testador usa a representação HTML para validar os resultados do teste inicial do teste de unidade (para certificar-se de que os resultados correspondam o que é esperado) e examinar o que causou um teste de unidade falhar durante execuções subseqüentes. Em uma falha, o HTML exibe a estrutura de dados original como bem como qual parte dos dados estrutura falha na validação e porquê. Isto é crítico para ajudar a depurar o problema.

A melhor maneira de testar a maioria dos cenários é utilizando a metodologia de teste "caixa-preta". Um teste de caixa-preta passa a entrada e saída de valida. Porque a saída para um cubo é um resultado da consulta, a entrada é a consulta. Você pode usar instruções MDX para consultar um cubo. Depois que o cubo interpreta a consulta MDX, ele retorna um resultado. O resultado é na forma de linhas e colunas que são uma representação das dimensões escolhidas para executar a consulta MDX. O resultado da consulta MDX pode ser bastante complexo, porque a consulta pode envolver muitas dimensões, resultando em uma variedade de linhas e colunas na saída. Os dados de estruturam escolhido para manter que os dados do cubo são um dicionário de CubeRow instâncias chaveados pelo nome da linha de cubo. A classe CubeRow contém duas estruturas de dados alternativas — usada depende da situação. Uma estrutura de dados é um dicionário de CubeTuple instâncias chaveados pelo nome da coluna de cubo. O CubeTuple é simplesmente um objeto que contém o nome da coluna do cubo e o valor da coluna determinada. Os objetos do dicionário de CubeTuble é usado quando a cubo determinada coluna contém um valor. A segunda estrutura de dados é outro dicionário, mapear um nome de linha para uma instância de CubeRow. Porque uma consulta MDX pode ter muitos níveis de dimensões de linha, CubeRow contém seu próprio dicionário de linha nome e instâncias de CubeRow.

Não são apenas os resultados do cubo armazenadas em um dicionário < String, CubeRow > instância, os resultados também são armazenados em uma cadeia de caracteres HTML. A seqüência de caracteres HTML permite que o testador têm uma representação visual dos resultados do cubo. Tabela HTML contém múltiplos níveis de cabeçalhos de coluna e linha, e as células da tabela HTML contêm os valores MDX. Figura 2 mostra o layout da representação HTML de um resultado de consulta MDX.

Figura 2 o Layout da representação HTML de um resultado de consulta MDX

   

Dimensão de coluna

Legenda 1 (valor 1)

Dimensão de coluna

Legenda 1 (valor 1)

Dimensão de coluna

Legenda 1 (valor 2)

Dimensão de coluna

Legenda 1 (valor 2)

   

Dimensão de coluna

Legenda 2 (valor 1)

Dimensão de coluna

Legenda 2 (valor 2)

Dimensão de coluna

Legenda 2 (valor 1)

Dimensão de coluna

Legenda 2 (valor 2)

Linha de dimensão

Legenda 1 (valor 1)

Linha de dimensão

Legenda 2 (valor 1)

Valor de resultado MDX Valor de resultado MDX Valor de resultado MDX Valor de resultado MDX

Linha de dimensão

Legenda 1 (valor 1)

Linha de dimensão

Legenda 2 (valor 2)

Valor de resultado MDX Valor de resultado MDX Valor de resultado MDX Valor de resultado MDX

Linha de dimensão

Legenda 1 (valor 2)

Linha de dimensão

Legenda 2 (valor 1)

Valor de resultado MDX Valor de resultado MDX Valor de resultado MDX Valor de resultado MDX

Linha de dimensão

Legenda 1 (valor 2)

Linha de dimensão

Legenda 2 (valor 2)

Valor de resultado MDX Valor de resultado MDX Valor de resultado MDX Valor de resultado MDX

BaseMDXTest contém o código para executar uma consulta MDX e construção de estrutura de dados do resultado MDX, bem como o representante XML. BaseMDXTest usa Microsoft.Analysis­Services.AdomdClient.dll, encontrada nas assembleias SQL Server SDK, para conectar-se ao cubo SSAS e executar as consultas MDX. BuildTemplate é o método que executa a consulta MDX e constrói o MDX resulta dicionário, bem como a representação de HTML. Em primeiro lugar, é estabelecida uma conexão ao cubo. A fim de estabelecer e abrir uma conexão, a seqüência de conexão é passada para uma instância de MicrosoftAnalysisServices.AdomdClient.AdomdConnection. O método aberto é chamado na instância de conexão recém-criado e a instância de conexão é retornado ao chamador. Depois que uma conexão é criada, uma instância do MicrosoftAnalysis­Services.AdomdClient.AdomdCommand método é estabelecido e é passado a seqüência de caracteres de consulta MDX e a instância de AdomdConnection. Uma chamada para o método AdomdCommand.ExecuteCellSet executa a consulta MDX contra a versão de teste de unidade do cubo e retorna uma instância de MicrosoftAnalysisServices.AdomdClient.CellSet (ver Listagem 6 no download de código).

Depois que a instância do conjunto de células é obtida, é feita uma verificação para garantir que o conjunto de resultados tem dois eixos. Eixo 0 contém as colunas e 1 eixo contém as linhas. Cada eixo contém uma coleção de objetos de posição. Uma posição representa uma tupla no eixo determinado e contém um ou mais objetos de membro. Um membro representa os cabeçalhos de coluna ou linha para a posição determinada (ver Listagem 7 no download de código).

Em seguida, o número de linhas e colunas retornadas pela consulta MDX é computado. Isto é feito tomando-se o número de linhas (a contagem de objetos de posição no eixo 1) mais o número de dimensões da coluna (CellSet.Axes[0].Posições [0].Members.Count). O número de colunas é adicionado às linhas porque quando representando os MDX resultados como uma tabela bidimensional, as colunas estão incluídas dentro do conjunto de linhas. Da mesma forma, o número de colunas é calculado tomando-se o número de objetos de posição no eixo 0 mais o número de dimensões de linha (ver Listagem 8 no download de código).

Dado o número de linhas e colunas, os dicionário de CubeRow objetos podem ser gerados bem como a representação HTML da saída de MDX. Listagem 9 no código de download contém o código para percorrer o conjunto de resultados MDX, criando o HTML e armazenar os resultados no dicionário de CubeRow. Em primeiro lugar, o número de linhas é dada laços através de. Se o número da linha é maior que o número de dimensões da coluna, então ele é conhecido que uma nova linha de MDX resultados está disponível. Em outras palavras, quando as linhas de cabeçalhos de coluna foram passadas, os dados MDX estão disponíveis. Neste ponto, um novo objeto CubeRow é criado.

O próximo passo é fazer um loop por cada coluna dentro da linha. Se o número da linha atual é inferior ao número de dimensões da coluna, em seguida, a linha atual é na verdade uma linha de cabeçalhos de coluna. Para o dicionário, as legendas de cabeçalho são concatenadas para cada local de coluna, separado por dois-pontos. Isto significa que se um cabeçalho é composto de várias dimensões, cada coluna será concatenada com a dimensão dada em ordem decrescente de resolução. A geração de HTML para um cabeçalho de coluna é mais simples. A legenda de dimensão simplesmente está rodeada pelas tags de cabeçalho de tabela HTML (Solid > < th ><). Para cada caso, a legenda de dimensão atual é obtida, obtendo o cabeçalho eixo (CellSet.Axis[0]) e acessar a posição de coluna (contagem de coluna atual menos a contagem atual de dimensão de linha) e o membro atual dentro dessa posição (contagem de linha atual).

Se o número da linha atual for maior que o número de dimensões da coluna, em seguida, os cabeçalhos de coluna já não está sendo processado. Em vez disso, o resultado MDX definir linha tuplas são próximo na fila para processamento. Semelhantes a colunas, que têm cabeçalhos, MDX resultado definir linhas também podem ter cabeçalhos. Se o número da coluna a ser processado é menor que o número de dimensões de linha, em seguida, um cabeçalho de linha está sendo processado. Para cada cabeçalho de linha, um novo dicionário < string, CubeRow > é criada, adicionado ao dicionário atual e definida como o resultado MDX atual dicionário. O que isto significa é que para cada cabeçalho de linha, existe um dicionário de linhas que contém mais dados do resultado MDX granulados.

Extrair a legenda de cabeçalho de linha é semelhante ao extrair a legenda de cabeçalho de coluna. A legenda de linha é recuperada do objeto membro no local atual coluna da posição na linha atual de CellSet.Axis[1]. A legenda de linha é a chave para o dicionário de CubeRows, e se o dicionário de CubeRow atual não tem a legenda de linha extraído, o objeto CubeRow é adicionado ao dicionário chaveado pela legenda de linha. Se a legenda de linha existir dentro do dicionário de CubeRow atual, o objeto CubeRow é obtido e definido como currentCubeRow.

Após a linha Membros legenda esgotadas (isto é, a contagem atual de coluna é maior que o número de dimensões de linha) e tem atravessadas as linhas de cabeçalho de coluna (isto é, a contagem de linha atual é maior que o número de dimensões da coluna), é hora de adicionar os valores de célula MDX ao objeto atual CubeRow. Cada combinação de um cabeçalho de coluna e o valor da coluna é considerada compõem uma única instância de CubeTuple. Cada CubeRow contém um dicionário de CubeTuple objetos alinhados com o cabeçalho de coluna. O cabeçalho de coluna é obtido de uma matriz de cabeçalhos de coluna anteriormente construído (Lembre-se de um cabeçalho de coluna é um dois-pontos -­delimitados por caracteres de todas as legendas de coluna concatenadas). O índice do cabeçalho da coluna é a contagem de coluna atual menos o número de dimensões de linha (a contagem total de coluna inclui as dimensões de linha). O valor atual do conjunto de células MDX é obtido, acessando o apropriado bidimensional (coluna, linha) ponto. Isto é baseado na contagem da coluna atual (menos o número de dimensões de linha) e a atual contagem de linha (menos o número de dimensões da coluna). Esse valor é adicionado para o objeto de CubeRow usando o método AddTuple, passando o cabeçalho de coluna e o valor da coluna. Ao mesmo tempo, a representação do HTML é atualizada, adicionando o valor da célula MDX entre tokens de dimensão (/td > < td ><) tabela HTML. Ver Figura 3 para uma representação gráfica do dicionário < string, CubeRow >.

O HTML e o dicionário de representação do modelo são persistentes para uma localização de arquivo previamente definido usando o método BaseMDXTest.PersistTemplate. Porque o modelo precisa ser validada manualmente pelo desenvolvedor do teste de unidade, o teste é considerado ter falhado, por isso é que o método BaseMDXTest.TestMDXQuery retorna false para o sucesso.

A Graphical Representation of the CubeRow Dictionary
Figura 3 representação gráfica do dicionário CubeRow

Uma vez que o modelo foi criado, execuções subseqüentes do mesmo teste são validadas contra o modelo armazenado anteriormente. Quando o método TestMDXQuery é chamado, primeiro é feita uma verificação para ver se um teste com o nome existe. Se ele faz, e uma nova criação de modelo não é solicitada (solicitando para recriar o modelo pode ocorrer se o modelo atual está incorreto), em seguida, o modelo de resultado do teste é carregado na memória. O modelo inclui a representação de objeto e a representação de HTML do conjunto de resultados MDX. O método BaseMDXTest.RunComparison executa a consulta MDX e compara os resultados contra o modelo armazenado. Os resultados da consulta MDX são percorridos da mesma forma como eram durante a criação do modelo. A principal diferença entre a criação do modelo original e a validação contra o modelo é que, em vez de criar o dicionário < string, CubeRow >, as pesquisas são feitas contra o modelo de dicionário, verificando se os mesmos resultados de consulta MDX existem. Quando um loop através das linhas e colunas, tabela HTML é criada da mesma forma como durante a criação do modelo, exceto que agora as células dentro da tabela HTML são coloridas. Uma célula verde indica que a célula coincide com o modelo original; uma célula vermelha mostra uma incompatibilidade. Por colorir as células e apresentá-las em uma tabela HTML, o verificador de unidade tem uma visão imediata por que o caso de teste passou ou falhou. Quando uma incompatibilidade for encontrada, um valor booleano (testPass) é definido como false para indicar que o caso de teste falhou.

Enquanto atravessando o MDX consulta resultados e validá-los contra o modelo de dicionário, cada CubeTuple (um objeto que contém a dimensão da coluna, nomes concatenados e o valor da coluna) encontraram é removido do atual CubeRow dicionário de objetos CubeTuple. Portanto, após todo o resultado da consulta MDX é passado, o modelo original dicionário deve ter CubeRow objetos com um vazio objetos do dicionário de CubeTuple se o resultado MDX foi uma partida completa. Caso contrário o resultado da consulta MDX novo faltava dados que estava contidos dentro o resultado original. O método BaseMDXTest.CheckForExtraDataInTemplate examina o modelo de dicionário para restantes CubeTuple objetos, executar recursivamente e retorna um valor de true se CubeTuple objetos permanecem. O testPass Boolean dentro do método RunComparison é definida para false se encontraram-se dados extras, e o caso de teste falhar.

Após o MDX resultados foram completamente atravessados e validados contra o modelo de dicionário, uma instância do cubo­ComparisonResult objeto é retornado. Ela é construída com o testPass Boolean e tabela HTML, mostrando o resultado. O método BaseMDXTest.TestMDXQuery usa CubeComparisonResult para construir uma página HTML, Visualizar a tabela HTML de resultado de consulta MDX original e a tabela de comparação de HTML. O HTML é mantido no sistema de arquivos, executando uma chamada ao método BaseMDXTest.PersistTestReport, que cria uma página da Web TestReport.html Resumo listando todas as execuções de teste e links para seu HTML resultam páginas, bem como um resumo do número de casos de teste que passaram e falharam.

Teste do cubo de compra

Usando ambos os componentes do quadro de teste de cubo — o código de criação de cubo (XMLAtoCube) e o MDX consultam modelo resultado (BaseMDXTest) — você pode criar casos de teste de unidade que validam o cubo. Embora o código para o framework é extenso, criar casos de teste é simples e direta. Listagem de 10 no código de download contém testes de unidade de amostra para validação do cubo compra. Esses casos de teste usar a estrutura de testes da Microsoft, mas qualquer estrutura de testes pode ser incorporada.

O objeto de teste de unidade (PurchaseCubeTest no exemplo) herda de BaseMDXTest. O construtor padrão do PurchaseCubeTest constrói BaseMDXTest com a URL do servidor do SSAS, onde se encontra o cubo e o diretório base para armazenar o modelo de resultado de consulta MDX e resultados dos testes subseqüentes.

Um método de [TestInitialize] é usado para criar a versão de teste de unidade do cubo compra. Ele usa a definição de XMLA do cubo original e cria-lo no teste de unidade servidor SSAS (targetServerName) usando um teste de unidade banco de dados (targetDatabaseName). Ele também aponta o URL da fonte de dados para a localização dos dados de dimensão e de fato teste. [TestInitialize] é executado apenas uma vez para uma determinado [TestClass], o que garante o cubo é criado apenas no início do teste.

Os casos de teste, se são executados dentro [TestMethod] métodos anotados. Cada caso de teste é simples. A consulta MDX é definida e executada usando o método BaseMDXTest.TestMDXQuery herdado, nomeando o caso de teste e passá-la a consulta MDX. TestMDXQuery retorna true se o teste passar ou false se não for, e um método IsTrue é usado para passar ou falhar o teste de unidade. Após todos os testes foram executados, o documento de teste HTML resultante pode ser aberto e podem ser examinados os casos de teste falhar. Figura 4 contém um exemplo de saída HTML de um dos testes.

The HTML Output of an Example Test
Figura 4 a saída HTML de teste de exemplo

Código testado corretamente

Embora não seja simples, nem um cubo OLAP pode ser unidade testada usando c#. A inclusão de ambos os Microsoft.AnalysisServices.dll e os arquivos de Microsoft.AnalysisServicesAdomdClient.dll dentro os assemblies de SQL Server fornece-lhe com as APIs para criar e consultar cubos SSAS. A arquitetura apresentada permite que você adicione um rico conjunto de testes de unidade que produz a saída em um formato legível por falhas do caso de teste podem ser identificadas rapidamente. O método do caso de teste de validação pelo modelo pode ser aplicado para outras arquiteturas de teste de unidade, onde a validação de saída não é simples. Exemplos destes gama de aplicações que dependem de persistência de banco de dados relacional tradicional, onde o modelo contém os dados esperados ser armazenado no banco de dados depois que o aplicativo é executado, para aplicativos de interface do usuário que armazenam o estado da interface do usuário em uma estrutura de dados e exibir a interface do usuário em um formulário HTML.

Não tenho certeza se Thomas Jefferson ou nossos pais fundadores compararia as liberdades de uma nação para os direitos de devidamente testado código, mas eu tenho certeza de seus usuários e supervisores ficaria felizes em saber que seu aplicativo foi corretamente colocado através dos seus ritmos.

Mark Nadelson é um desenvolvedor de software profissional com 22 anos de experiência nas indústrias de telecomunicações, Internet e finanças. Ao longo de sua carreira, ele usou uma série de linguagens de programação como assembly, C, C++, Java e c#. Nadelson também é o autor de dois livros e uma série de artigos técnicos.

Agradecemos aos seguintes especialistas técnicos pela revisão deste artigo: David Neigler (SAC Capital Advisors LP) e Joe Sampino(SAC Capital Advisors LP)
David Neigler é um gerente de desenvolvimento da indústria de serviços financeiros, trabalhando no SAC Capital Advisors LP.  Seu foco é o desenvolvimento de sistemas que resolver problemas de grande volume de dados enfrentados por empresas financeiras que fazem grandes volumes de negociação.

Joe Sampino trabalha no SAC Capital Advisors LP, desenvolvimento de plataformas de inteligência de negócios corporativos para grandes bancos e empresas de investimento.  Ele cria e gerencia os armazéns de dados, cubos do Analysis Services SQL Server e sistemas de relatórios/análise de dados para interno, externo, regulamentação e conformidade precisa. "