Cet article a fait l'objet d'une traduction automatique.
SQL Server
Tests unitaires des cubes OLAP SQL Server à l'aide de C#
Je me sens un peu comme Thomas Jefferson, quand je dis, "nous tenons ces vérités comme évidentes, que tous les code possède certains droits inaliénables, et que parmi ces droits est la capacité d'être soigneusement l'unité testée de façon simple et concise afin de bogues soient facilement reconnaissables et les interruptions de production minimisées. » Un peu dramatique, oui, mais il obtient mon point dans l'ensemble.
Bien sûr, la plupart des développeurs croient leur code devrait être testées, mais que se passe-t-il lorsque la définition du « code » est floue ? Telle était la situation je retrouvai dans récemment lorsque confrontés à un problème complexe et chargé de trouver une solution. Un groupe de développeurs a participé à la rédaction d'un complexe traitement analytique en ligne (OLAP) de cube à l'aide de SQL Server Analysis Services (SSAS). Ce cube avait toutes les nombreuses dimensions, attachées à une table de faits extrêmement complexe. Parce que les développeurs étaient très habiles à développer des cubes, ils ont réussi à reconstituer le cube, mais valider les résultats de leurs requêtes MDX (Multidimensional Expressions) est une tâche ardue. La difficulté a été aggravée par un certain nombre de facteurs, y compris la quantité de données dans la table de faits et les dimensions, ainsi que le temps et les ressources nécessaires pour construire le cube informatiques. Une fois que le cube a été construit, les résultats (produites par les requêtes MDX) ont été envoyés aux utilisateurs. Si les utilisateurs trouvent une issue avec les données, il faudrait beaucoup de temps pour traquer le problème. Aussi, une fois que le problème sous-jacent a été découvert et corrigé, le cube devra être régénéré. Pour rendre les choses pire, si les dimensions ont été ajoutées, la table de faits sous-jacente a été mis à jour ou le cube a été construit à l'aide de différentes agrégations, il y n'avait aucun moyen de déterminer tous les effets de ces changements. Un changement d'apparence innocent pourrait avoir un effet en cascade et de grande envergure sur les requêtes au cube.
La solution pour l'énigme du cube est de créer un environnement et un processus dans lequel vous pouvez scène dimensions du cube et les faits à l'aide d'une quantité limitée de données et exécuter des requêtes sur le cube à l'aide de la version de production du schéma du cube. Idéalement, la version d'essai du cube aurait créée de toutes pièces chaque fois que les tests unitaires exécutent, éliminant la possibilité d'effets secondaires qui se produisent d'objets préexistants. Autres conditions requises pour l'infrastructure de tests unitaires (et vraiment, elles s'appliquent à la plupart des cadres test unitaire indépendamment de l'application cible) doit s'assurer les validations de test sont répétables et si la panne survient à rapidement et facilement identifier pourquoi le test a échoué (ayant l'esample dire "a échoué, car les données ne correspondent pas" est loin d'être idéale).
Dans cet article, je présenterai un cadre qui vous permet de créer une suite de tests unitaires pour valider la sortie MDX d'un cube OLAP. L'architecture décrite permet la création d'un cube à l'aide d'un schéma existant, au sein de sa propre base de données de test unitaire, recréé à chaque exécution de la suite de tests. Il vous permet également de fournir des requêtes MDX qui sont exécutées sur la version de test unitaire nouvellement formé du cube. En outre, il valide les résultats contre un modèle préexistant et les présente sous format HTML simple. Ce modèle de scénario de test de validation contre un modèle peut être étendu aux cadres de test unitaire dans lequel les résultats sont vastes et complexes.
Vue d'ensemble du cube
Avant de plonger dans la solution pour la question test cube, je vais brièvement sur les concepts et les composants qui constituent un cube. Les cubes sont un moyen d'accéder rapidement aux données détenues au sein d'un entrepôt de données. Cubes, organisent et résument les données dans une structure multidimensionnelle. Les cubes sont la principale composante de la technologie OLAP, et ils fournissent un mécanisme facile à utiliser pour interroger les données avec des temps de réponse rapide et prévisible. Un cube est composé des données de dimension et les mesures (faits numériques). La table centrale dans un cube est connue comme la table de faits, et c'est la source de mesures du cube. Les tables de dimension sont référencées par la table de faits, et ils contiennent les niveaux hiérarchiques de l'information qui peut être interrogé. La hiérarchie de dimension permet aux utilisateurs de poser des questions à un niveau élevé. Ensuite, les utilisateurs en utilisant la hiérarchie de la dimension, peuvent obtenir pour plus de détails.
Cubes contenus dans une base de données. Les objets qui composent la structure du cube pour une base de données sont les suivantes :
- Sources de données : Ce sont les sources d'information pour être chargé dans le cube.
- Mesures : Ce sont les valeurs numériques représentées dans le cube. Ils peuvent être des dates, mais sont habituellement numériques avec différents niveaux d'agrégation (telles que Sum, Max, Min et Count).
- Dimensions : Voici les attributs associés aux mesures. Données commerciales, les noms des clients et les régions géographiques sont des exemples courants de dimensions.
- Partitions : Une partition définit une partie des données fait chargées dans un groupe de mesures. En créant plusieurs partitions, le cube peut être traité en parallèle et stockés et interrogé séparément, ce qui améliore les performances. Vous pouvez également retraiter des partitions individuelles sans affecter les autres partitions.
- Rôles de cube : Chaque cube devrait avoir au moins un rôle de cube pour permettre l'accès aux utilisateurs finals. Rôles peuvent donner accès à toutes les données ou un sous-ensemble des données stockées dans le cube basé sur un ID utilisateur individuel ou un groupe Active Directory.
La définition de schéma d'un cube peut être extraites SSAS sous forme de XML for Analysis (XMLA). XMLA est un protocole basé sur SOAP XML qui donne accès au cube sur HTTP. La définition de XMLA contienne tous les détails pour chacun des objets cinq cube décrits précédemment. XMLA vous permet de recréer le cube sur différentes bases de données ou serveurs rapidement et facilement. C'est la pierre angulaire qui est créé le cube unité-testables.
Une fois que le cube est créé et traité, les mesures données peuvent être interrogées à l'aide d'un mélange et un match de football de la variété des dimensions, utilisé pour le créer. Les cubes sont interrogés à l'aide de la syntaxe MDX susmentionnée. Comme une requête SQL, une requête MDX contient une demande de données (en utilisant l'instruction SELECT), un point de données (à l'aide de l'instruction FROM) et un filtre de données facultatifs (à l'aide de la clause WHERE). Voici un exemple de base :
SELECT {[<axis specification using Measures>]...} ON AXIS(0),
{[<axis specification using a dimension hierarchy>]...} ON AXIS(1)
FROM [<cube>]
WHERE (<filter specification>)
Le Cube de vente exemple
J'ai créé un cube exemple qui vous permet de rapidement interroger des données ventes pour divers magasins à différentes dates par divers clients (voir Figure 1).
Figure 1 schéma de base de données de Cube vente exemple
Le cube est composé de quatre tables de dimension, se connecter à une table de faits. Pour plus de simplicité, la table de faits contient une mesure appelée quantité, ce qui représente la quantité d'un élément donné, vendu à un client donné dans un magasin sur une date d'achat donné. Avec cette configuration du cube, l'utilisateur peut interroger rapidement faits divers à l'aide de différentes dimensions. Par exemple, les dirigeants d'entreprise peuvent avoir une idée claire dont les produits se vendent dans les magasins, ou ils peuvent entrer dans les détails tels que laquelle éléments vendent meilleurs durant une année donnée ou un mois. Ayant un grand nombre de dimensions permet une données de vente vue exécutif dans une variété de façons, fournissant la meilleure idée de la performance des magasins.
Création de la Version de Test unitaire du Cube
Comme mentionné, la définition de cube peut être extraites de SSAS sous la forme d'un document XMLA. Ce document XMLA est utilisé pour créer la version de test unitaire du cube. À l'aide de la définition de la production du cube assure que les essais exercera avec précision toutes les fonctionnalités du cube en question. Vous l'interface avec le moteur SSAS à l'aide de Microsoft.AnalysisServices.dll, qui se trouve dans les assemblys SDK SQL Server .
L'objet utilisé pour générer le cube est XMLAtoCube. Le constructeur prend dans un répertoire de configuration de base sous lequel est stocké le XMLA. La structure de répertoire, j'ai choisi pour abriter le cube XMLA est < répertoire de base > \ < nom du serveur production > \< nom de base de données de production >.
XMLAtoCube contient une méthode publique, CreateCubeFromXMLA, qui prend les paramètres suivants (voir code de la méthode dans Listing 1 dans le fichier Listings.zip dans le téléchargement de code qui l'accompagne) :
- NomServeurSource : Le nom du serveur de production qui contient le cube.
- TargetServerName : Le nom du serveur qui hébergera la version de test unitaire du cube.
- SourceDatabaseName : Le nom de la base de données de production qui contient le cube.
- NomBaseDeDonnéesCible : Le nom de la base de données qui hébergera la version de test unitaire du cube.
- DataSourceProviderDefinition : L'URL de chaîne de connexion qui indique la version de test unitaire du cube à l'emplacement de ses dimensions de la source et la table de faits. Ce sera la source de données réduite pour le test unitaire.
Tout d'abord, CreateCubeFromXMLA établit une connexion à la version du serveur test unitaire analytics et supprime la version de test unitaire de la base de données du cube, si celui-ci existe déjà. L'abandon de la base de données est important car il garantit que les essais sont effectués sur un environnement sain sans tout contam artefacts résiduelleabroger le résultat. La connexion au serveur de Google analytics est exécutée au sein de la méthode ConnectToServer à l'aide d'une instance de Microsoft.AnalysisServices.Server. Un appel à Connect (chaîne de connexion < >) en utilisant le nom de serveur de test unitaire transmis en établit la liaison (voir Listing 2 dans le téléchargement de code). Une fois la connexion au serveur est établie avec succès, la version de test unitaire de la base de données de cube est supprimée si elle existe déjà. Cette suppression se faite avec la méthode DropDatabase, qui est passée à l'instance connectée de serveur et le nom de la base de données de test unitaire à baisser (TargetServerName). DropDatabase veille à ce que l'instance de serveur est connecté, lève les yeux du Microsoft.AnalysisServices.Database en utilisant le nom de base de données de test unitaire passé et, si la base de données existe (l'instance de base de données n'est pas null), la base de données est supprimé (voir Listing 3 dans le téléchargement de code).
L'étape suivante consiste à prendre XMLA définition du cube original et de générer la version de test unitaire. La version de test unitaire contient les mêmes dimensions, les hiérarchies de dimension, les mesures, les cloisons, les rôles et ainsi de suite comme le cube original. La différence est qu'il est généré dans une nouvelle base de données pointant vers un autre emplacement pour les données de sa source. La méthode AddCubeToDatabase crée le cube de test (voir Listing 4 dans le téléchargement de code). AddCubeToDatabase lit la définition de XMLA dans le système de fichiers à l'aide de la convention de nommage mentionnée précédemment. Le nom du fichier XMLA est passé à une instance de XmlTextReader à construction. Le XMLA est lue en utilisant la méthode Microsoft.AnalysisServices.Utils.Deserialize, qui est passée le XmlTextReader et une instance nouvellement créée de Microsoft.AnalysisServices.Database. L'instance d'objet de base de données contient à présent la définition complète du cube, mais cette définition est toujours source de données et le nom de base de données du cube original. Pointant vers la base de données de test unitaire implique simplement de définir les propriétés Name et ID de la « base de données au nom de test unitaire de base de données » (NomBaseDeDonnéesCible) paramètre. Cette base de données peut ensuite être ajouté à l'instance du serveur test unitaire analytics en appelant Server.Databases.Add (< database de test d'unité >) suivie de la méthode Database.Update.
Après avoir créé la base de données, vous devez mettre à jour la source de données du cube à la collecte de données de test d'unité externe. L'instance de base de données possède une liste d'instances de source de données (habituellement juste une source de données est associée à un cube) et la chaîne de connexion de test unitaire est utilisée pour remplacer la chaîne de connexion contenue dans la définition de XMLA. Après que la chaîne de connexion est remplacée, un appel à la méthode DataSource.Update il actualise dans le serveur SSAS. À ce stade, la personnalisation de la définition de XMLA est complétée et les pièces restantes du cube (DataSourceView, Dimension et Cube) sont mis à jour et traitées.
Après que l'appel à AddCubeToDatabase est complet, la version de test unitaire du cube a été créée au sein du serveur spécifié à l'aide de la base de données de test unitaire choisi. Il pointe vers un jeu personnalisé de données sources. Bien que le cube a été créé, il est toujours vide. Afin de remplir les dimensions avec les données sources, les dimensions doivent être traitées. La méthode ProcessDimensions est appelée et passée de l'instance de base de données. Toutes les Dimensions de la base de données sont traitées à l'aide de la méthode Dimension.Process(ProcessType.ProcessFull). Une fois les dimensions ont été traitées avec succès, les cubes dans le test unitaire de base de données sont traitées à l'aide de la méthode de ProcessCube. Comme ProcessDimensions, ProcessCube prend l'instance de base de données, effectue une boucle sur tous les cubes dans la base de données et appelle Cube.Process(ProcessType.ProcessFull) (voir liste 5 dans le téléchargement de code). À ce stade, le cube de test unitaire a été créé et rempli avec les données de test ciblé. L'étape suivante consiste à exécuter des tests contre elle pour s'assurer que le cube se comporte comme prévu.
Valider le Cube
Bien que la solution de validation est ciblée pour le cube, le modèle de conception utilisé peut appliquer d'autres infrastructures de tests unitaires ainsi. Le modèle employé met à l'essai à l'aide de la validation du modèle. Autrement dit : Lorsque le test est exécuté, une structure de données contenant les résultats est créée et validée par rapport à une version déjà en mémoire de la structure de données qui a été jugée correcte. Parce qu'il est difficile de valider une structure de données binaires, une représentation HTML de la structure est présentée pour le testeur unitaire. Le testeur utilise la représentation HTML pour valider les résultats de l'épreuve initiale du test unitaire (pour s'assurer que les résultats correspondent à ce qui est attendu) et d'examiner ce qui a causé un test unitaire à l'échec lors des exécutions suivantes. En cas de panne, le code HTML affiche la structure originale des données sous la forme ainsi que la pièce des données structure de validation a échoué et pourquoi. Ceci est crucial pour aider à déboguer le problème.
La meilleure façon de tester la plupart des scénarios utilise la méthodologie des tests « boîte noire ». Un test boîte noire passe d'entrée et valide la sortie. Parce que la sortie d'un cube est un résultat de la requête, l'entrée est de la requête. Vous utilisez des instructions MDX pour interroger un cube. Après que le cube interprète la requête MDX, elle retourne un résultat. Le résultat est sous forme de lignes et de colonnes qui sont une représentation des dimensions choisi pour l'exécution de la requête MDX. Le résultat de la requête MDX peut être assez complex, parce que la requête peut comporter plusieurs dimensions, résultant en une variété de lignes et de colonnes dans la sortie. Les données de structurent choisie pour organiser que les données du cube sont un dictionnaire d'instances de CubeRow par le nom de la ligne de cube. La classe CubeRow contient deux structures de données alternatives — celle utilisée dépend de la situation. Une structure de données est un dictionnaire des instances CubeTuple indexé par le nom de la colonne de cube. Le CubeTuple est tout simplement un objet qui contient le nom du cube de la colonne et la valeur de la colonne donnée. Les objets du dictionnaire de CubeTuble est utilisé lorsque la colonne donnée cube contient une valeur. La seconde structure de données est un autre dictionnaire, mapper un nom de ligne à une instance de CubeRow. Parce qu'une requête MDX peut avoir plusieurs niveaux de dimensions rangée, CubeRow contient son propre dictionnaire du nom de la ligne et les instances de CubeRow.
Sont non seulement les résultats du cube stockés dans un dictionnaire < String, CubeRow > instance, les résultats sont également stockés dans une chaîne HTML. La chaîne HTML permet le testeur d'avoir une représentation visuelle des résultats cube. La table HTML contient plusieurs niveaux d'en-têtes de lignes et de colonnes, et les cellules d'un tableau HTML contiennent les valeurs MDX. La figure 2 montre la disposition de la représentation HTML d'un résultat de requête MDX.
Figure 2 la disposition de la représentation HTML d'un résultat de requête MDX
Dimension de colonne Légende 1 (valeur 1) |
Dimension de colonne Légende 1 (valeur 1) |
Dimension de colonne Légende 1 (valeur 2) |
Dimension de colonne Légende 1 (valeur 2) |
||
Dimension de colonne Légende 2 (valeur 1) |
Dimension de colonne Légende 2 (valeur 2) |
Dimension de colonne Légende 2 (valeur 1) |
Dimension de colonne Légende 2 (valeur 2) |
||
Dimension de rangée Légende 1 (valeur 1) |
Dimension de rangée Légende 2 (valeur 1) |
Valeur de résultat MDX | Valeur de résultat MDX | Valeur de résultat MDX | Valeur de résultat MDX |
Dimension de rangée Légende 1 (valeur 1) |
Dimension de rangée Légende 2 (valeur 2) |
Valeur de résultat MDX | Valeur de résultat MDX | Valeur de résultat MDX | Valeur de résultat MDX |
Dimension de rangée Légende 1 (valeur 2) |
Dimension de rangée Légende 2 (valeur 1) |
Valeur de résultat MDX | Valeur de résultat MDX | Valeur de résultat MDX | Valeur de résultat MDX |
Dimension de rangée Légende 1 (valeur 2) |
Dimension de rangée Légende 2 (valeur 2) |
Valeur de résultat MDX | Valeur de résultat MDX | Valeur de résultat MDX | Valeur de résultat MDX |
BaseMDXTest contient le code pour l'exécution d'une requête MDX et la construction de la structure de données MDX résultat ainsi que le XML représentant. BaseMDXTest utilise Microsoft.AnalysisServices.AdomdClient.dll, trouvé dans les assemblys SDK SQL Server , se connecter au cube SSAS et exécuter les requêtes MDX. BuildTemplate est la méthode qui exécute la requête MDX et construit le MDX traduire dictionnaire ainsi que la représentation HTML. Tout d'abord, une connexion au cube est établie. Afin d'établir et d'ouvrir une connexion, la chaîne de connexion est passée à une instance de MicrosoftAnalysisServices.AdomdClient.AdomdConnection. La méthode Open est ensuite appelée sur l'instance de connexion nouvellement créée et l'instance de connexion est retournée à l'appelant. Une fois qu'une connexion est créée, une instance de le MicrosoftAnalysisServices.AdomdClient.AdomdCommand méthode est établie et est transmis à la chaîne de requête MDX et l'instance de l'objet AdomdConnection. Un appel à la méthode AdomdCommand.ExecuteCellSet exécute la requête MDX contre la version de test unitaire du cube et retourne une instance de MicrosoftAnalysisServices.AdomdClient.CellSet (voir Listing 6 dans le téléchargement de code).
Après avoir récupéré l'instance de l'objet CellSet, un contrôle est effectué pour s'assurer que le jeu de résultats comporte deux axes. Axe 0 contient les colonnes et axe 1 contient les lignes. Chaque axe contient une collection d'objets de Position. Une Position représente un tuple sur l'axe donné et contient un ou plusieurs objets de membre. Un membre représente les en-têtes de colonne ou de ligne à la Position donnée (voir Listing 7 dans le téléchargement de code).
Ensuite, le nombre de lignes et de colonnes retournées par la requête MDX est calculée. Ceci est fait en prenant le nombre de lignes (le nombre d'objets de Position sur l'axe 1) plus le nombre de dimensions colonne (CellSet.Axes[0].Postes [0].Members.Count). Le nombre de colonnes est ajouté aux lignes car lorsque représentant les résultats MDX sous forme de tableau à deux dimensions, les colonnes sont incluses dans le jeu de lignes. De même, le nombre de colonnes est calculé en prenant le nombre d'objets de Position sur l'axe 0 plus le nombre de dimensions de la ligne (voir liste 8 dans le téléchargement de code).
Vu le nombre de lignes et de colonnes, les objets du dictionnaire de CubeRow peuvent être générés ainsi que la représentation HTML de la sortie MDX. Le Listing 9 dans le code de téléchargement contient le code pour qui traversent le jeu de résultats MDX, en créant le code HTML et en enregistrant le résultat dans le dictionnaire de CubeRow. Tout d'abord, le nombre de lignes est bouclé. Si le numéro de ligne est supérieur au nombre de dimensions de la colonne, puis on sait qu'une nouvelle ligne de résultats MDX est disponible. En d'autres termes, quand les lignes d'en-têtes de colonne ont été passées, les données MDX sont disponibles. À ce stade, un nouvel objet CubeRow est créé.
L'étape suivante consiste à effectuer une boucle sur chaque colonne de la ligne. Si le numéro de ligne actuel est inférieur au nombre de dimensions de la colonne, puis la ligne actuelle est en fait une ligne d'en-têtes de colonne. Pour le dictionnaire, les légendes de l'en-tête sont concaténées pour chaque emplacement de colonnes, séparée par un deux-points. Cela signifie que si un en-tête est composé de multiples dimensions, chaque colonne sera concaténée avec la dimension donnée par ordre décroissant de résolution. La génération de HTML pour un en-tête de colonne est plus simple. La légende de dimension est simplement entourée par les balises d'en-tête de la table HTML (< th >< /th >). Pour chaque cas, la légende de dimension actuelle est récupérée en obtenant l'en-tête axe (CellSet.Axis[0]) et accéder à la position de la colonne (actuelle colonne count moins le nombre de dimension de lignes actuel) et le membre actuel dans cette Position (nombre actuel de lignes).
Si le numéro de ligne actuel est supérieur au nombre de dimensions de colonne, puis les en-têtes de colonne est traité n'est plus. Au lieu de cela, le résultat MDX définissez tuples sont ensuite en ligne pour le traitement de la ligne. Similaires aux colonnes qui ont des en-têtes, lignes de jeu MDX résultat peut-être aussi en-têtes. Si le numéro de la colonne en cours de traitement est inférieur au nombre de dimensions de rangée, un en-tête de ligne est traité. Pour chaque en-tête de ligne, un nouveau dictionnaire < string, CubeRow > est créé, ajoutés au dictionnaire actuel et défini comme le résultat actuel de MDX Dictionary. Cela signifie que, pour chaque en-tête de ligne, il existe un dictionnaire de lignes qui contient de plus des données de résultat granules MDX.
Extraire la légende d'en-tête de ligne est similaire à l'extraction de la légende d'en-tête de colonne. La légende de la ligne est Récupérée de l'objet membre à l'emplacement actuel de la colonne postées à la ligne actuelle du CellSet.Axis[1]. La légende de la ligne est la clé pour le dictionnaire de CubeRows, et si le dictionnaire de CubeRow actuel n'a pas la légende de la ligne extraite, l'objet CubeRow est ajouté au dictionnaire indexé par la légende de la ligne. Si la légende de la ligne existe dans le dictionnaire de CubeRow actuelle, l'objet CubeRow est récupérée et défini comme currentCubeRow.
Après la ligne, les membres de la légende ont été épuisées (c'est-à-dire, le nombre de colonne actuel est supérieur au nombre de dimensions de la ligne) et les lignes d'en-tête de colonne ont été parcourus (autrement dit, le nombre de lignes actuel est supérieur au nombre de dimensions de la colonne), il est temps d'ajouter des valeurs de cellule MDX à l'objet CubeRow. Chaque combinaison d'un en-tête de colonne et la valeur de colonne est considérée comme forment une seule instance de CubeTuple. Chaque CubeRow contient un dictionnaire d'objets CubeTuple par l'en-tête de colonne. L'en-tête de colonne est extraites d'un tableau d'en-têtes de colonne déjà construit (rappeler un en-tête de colonne est un colon -délimitée par la chaîne de toutes les légendes de colonne concaténés). L'index de l'en-tête de colonne est le nombre de colonne actuel moins le nombre de dimensions de rang (le nombre de colonnes total inclut les dimensions de la ligne). La valeur actuelle de MDX CellSet est récupérée en accédant à l'approprié à deux dimensions (colonne, ligne) point. Ceci est basé sur le nombre de colonne actuel (moins le nombre de dimensions de la ligne) et le nombre actuel de lignes (moins le nombre de dimensions de la colonne). Cette valeur est ajoutée à l'objet CubeRow à l'aide de la méthode AddTuple, en lui passant l'en-tête de colonne et la valeur de la colonne. Dans le même temps, la représentation HTML est mis à jour en ajoutant la valeur de cellule MDX entre jetons de dimension (/td > < td ><) table HTML. Voir Figure 3 pour une représentation graphique du dictionnaire < string, CubeRow >.
Le dictionnaire et le HTML de représentation du modèle sont rendues persistantes dans un emplacement de fichier défini précédemment à l'aide de la méthode BaseMDXTest.PersistTemplate. Parce que le modèle doit être validé manuellement par le développeur de tests unitaires, le test est considéré comme ayant échoué, c'est pourquoi la méthode BaseMDXTest.TestMDXQuery retourne la valeur false pour le succès.
Représentation graphique de la figure 3 du dictionnaire CubeRow
Une fois que le modèle a été créé, les exécutions suivantes de la même épreuve sont validées le modèle précédemment stocké. Lorsque la méthode TestMDXQuery est appelée, il est tout d'abord vérifié s'il existe un test avec le nom donné. Si il le fait et une nouvelle création de modèle n'est pas demandée (demandant à recréer le modèle peut survenir si le modèle actuel est incorrect), puis le modèle de résultat de test est chargé en mémoire. Le modèle inclut la représentation de l'objet et la représentation HTML du jeu de résultats MDX. La méthode BaseMDXTest.RunComparison exécute la requête MDX et compare les résultats avec le modèle stocké. Résultats de la requête MDX sont traversés de la même manière qu'ils l'étaient lors de la création du modèle. La principale différence entre la création du modèle original et la validation par le modèle, c'est qu'au lieu de créer le dictionnaire < string, CubeRow >, les recherches sont faites contre le modèle de dictionnaire, pour vérifier si les résultats de la requête MDX mêmes existent. Lorsqu'une boucle dans les lignes et colonnes, le tableau HTML est créé la même manière comme lors de la création de modèles, sauf les cellules dans le tableau HTML sont maintenant de couleur. Une cellule verte indique que la cellule correspond au modèle original ; un globule rouge montre une incohérence. De colorier les cellules et en les présentant dans un tableau HTML, le testeur unitaire a une vue immédiate de pourquoi l'esample réussite ou l'échec. Chaque fois une non concordance est trouvée, une valeur booléenne (testPass) a la valeur false pour indiquer le cas de test a échoué.
Lorsque vous traversez le MDX interroger les résultats et valider leur contre le gabarit Dictionary, chaque CubeTuple (un objet qui contient la dimension de la colonne, les noms concaténés et valeur de la colonne) trouvent est supprimé dans le dictionnaire actuel de CubeRow d'objets CubeTuple. C'est pourquoi, après que tout le résultat de requête MDX est passé, le modèle d'origine dictionnaire devrait avoir CubeRow objets avec un dictionnaire de CubeTuple des objets vides si le résultat MDX a été un match complet. Dans le cas contraire, le nouveau résultat de la requête MDX avait manque de données qui a été inclus dans le résultat initial. La méthode BaseMDXTest.CheckForExtraDataInTemplate examine le modèle de dictionnaire pour le restant des objets CubeTuple, l'exécution de manière récursive et retourne la valeur true si les objets CubeTuple restent. Le testPass Boolean dans la méthode de RunComparison a la valeur false si des données supplémentaires sont trouvées, le cas de test échoue.
Après le MDX résultats ont été entièrement parcourus et validées par rapport au modèle Dictionary, une instance du CubeComparisonResult objet est retourné. Il est construit avec le testPass Boolean et la table HTML montrant le résultat. La méthode BaseMDXTest.TestMDXQuery utilise CubeComparisonResult pour générer une page HTML montrant la table HTML originale du résultat de requête MDX et la table HTML de comparaison. Le HTML est rendu persistant dans le système de fichiers en exécutant un appel à la méthode BaseMDXTest.PersistTestReport, qui crée une TestReport.html analytique Web page répertoriant toutes les séries de tests et entraîner des liens vers leur HTML pages, ainsi qu'un résumé du nombre de cas de test passé et a échoué.
Test achat Cube
En utilisant les deux composantes de l'infrastructure de test cube — le code de création cube (XMLAtoCube) et le MDX requête modèle de résultat (BaseMDXTest), vous pouvez créer des cas de tests unitaires qui valident le cube. Bien que le code pour le cadre est vaste, créant les cas de test est simples et clairs. Liste 10 dans le code de téléchargement contient des tests unitaires échantillon pour validation du cube achat. Ces cas de test utilise l'infrastructure de test de Microsoft, mais toute infrastructure de test peut être incorporé.
L'objet de tests unitaires (PurchaseCubeTest dans l'exemple) hérite de BaseMDXTest. Le constructeur par défaut de PurchaseCubeTest construit BaseMDXTest avec l'URL du serveur SSAS où se trouve le cube et le répertoire de base dans lequel stocker le modèle de résultat de requête MDX et les résultats des tests ultérieurs.
Une méthode [TestInitialize] est utilisée pour créer la version de test unitaire du cube achat. Il utilise la définition de XMLA du cube original et il crée sur le serveur SSAS de test unitaire (targetServerName) à l'aide d'un test unitaire de base de données (NomBaseDeDonnéesCible). Il souligne également l'emplacement des données test dimension et fait l'URL de données source. [TestInitialize] est exécutée une seule fois pour une donnée [TestClass], qui assure le cube est créé seulement au début du test.
Les cas de test se sont exécutés au sein de [TestMethod] méthodes annotées. Chaque cas de test est simple. La requête MDX est définie et ensuite exécutée à l'aide de la méthode héritée de BaseMDXTest.TestMDXQuery, nommant le cas de test et en lui transmettant la requête MDX. TestMDXQuery retourne true si le test réussit, ou false si ce n'est pas, et une méthode Assert.IsTrue est utilisée pour la réussite ou échec du test unitaire. Après que tous les tests ont été exécutés, le document de test HTML qui peut être ouverts et les cas de test défaillant peut être examinés. Figure 4 contient un exemple de sortie HTML de l'un des tests.
Figure 4 la sortie HTML d'un exemple Test
Code correctement testé
Bien que ce n'est pas simple, même un cube OLAP peut être testées à l'aide de c#. L'inclusion de la Microsoft.AnalysisServices.dll et les fichiers de Microsoft.AnalysisServicesAdomdClient.dll au sein des assemblées SQL Server vous fournit les API pour la création et l'interrogation des cubes SSAS. L'architecture présentée vous permet d'ajouter un riche ensemble de tests unitaires qui produit une sortie dans un format lisible donc échecs de cas de test peuvent être rapidement identifiés. La méthode de scénario de test de validation de modèle peut être appliquée vers d'autres architectures de test unitaire où la validation de la sortie n'est pas simple. Exemples de ces gamme d'applications qui reposent sur la persistance des bases de données relationnelles traditionnelles où le modèle contient les données devraient être stockées dans la base de données après l'exécution de l'application, à des demandes de prestations qui stockent l'état de l'interface utilisateur dans une structure de données et affichent l'interface utilisateur dans un formulaire HTML.
Je ne suis pas tout à fait sûr si Thomas Jefferson ou nos pères fondateurs serait comparer les libertés d'une nation aux droits des correctement testé le code, mais je suis sûr que vos utilisateurs et superviseurs serait heureux de savoir que votre demande a été correctement mis à l'épreuve.
Mark Nadelson est un développeur de logiciels professionnels avec 22 ans d'expérience dans les industries de télécommunications, Internet et la finance. Tout au long de sa carrière, il a utilisé un certain nombre de langages de programmation dont l'Assemblée, C, C++, Java et c#. Nadelson est également l'auteur de deux livres et un certain nombre d'articles techniques.
Merci aux experts techniques suivants d'avoir relu cet article : David Neigler (SAC Capital Advisors, LP) et Joe Sampino(SAC Capital Advisors LP)
David Neigler est responsable du développement dans le secteur des services financiers, travaillant au SAC Capital Advisors LP. Son objectif est le développement de systèmes capables de résoudre les problèmes des grandes données financières entreprises qui font des gros volumes de négociation.
Joe Sampino travaille au SAC Capital Advisors LP, développement de plates-formes d'entreprise business intelligence pour les grandes banques et entreprises d'investissement. Il crée et gère des entrepôts de données, cubes de SQL Server Analysis Services et systèmes d'analyses/rapports de données pour les internes, externes, réglementation et conformité a besoin. »