Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 47

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 48

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 47

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 48

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 47

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 48

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 47

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 48

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 47

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 48

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 47

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 48

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 47

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 48

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 47

Warning: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead in /homepages/28/d448670958/htdocs/wp-content/plugins/latex/latex.php on line 48

This post has already been read 2042 times!

SSISTester

Quand j'ai commencé à réfléchir à une infrastructure de test pour les packages SSIS, j'ai trouvé trois aspects importants. Tout d'abord, je voulais avoir un UX semblable à l'écriture de tests en utilisant l'infrastructure de test de Visual Studio , donc la méthode typique mettant en cause le programme d'installation, de vérification et de nettoyage (aka le démontage) étapes devaient être appliqués. Deuxièmement, je voulais utiliser outils existantes et éprouvées pour écrire, d'exécuter et de gérer des tests. Une fois de plus, Visual Studio est le choix évident. Et Troisièmement, je voulais être en mesure de tests de code en c#. Dans cet esprit que j'ai écrit SSISTester, une bibliothèque .NET qui se trouve sur le dessus le runtime SSIS et expose une API qui vous permet d'écrire et d'exécuter des tests pour les packages SSIS. Les principaux composants logiques de la bibliothèque sont dépeints dans Figure1.

Figure 1 composants logiques de la bibliothèque de SSISTester

Le dépôt de paquets est utilisé pour stocker les premières représentations XML des paquets de la cible. Chaque fois qu'un test est exécuté, une nouvelle instance de la classe Microsoft.SqlServer.Dts.Runtime.Package est désérialisée à partir XML avec tous les champs et les propriétés leurs valeurs par défaut. Ceci est important parce que vous ne voulez pas différents tests qui ciblent le même package pour réutilisation accidentellement toute valeur définie par tests précédents.

Les instances de classes de test sont stockés dans le référentiel de Test. Ces classes contiennent des méthodes qui implémentent vos cas de test. Lorsqu'un test est exécuté, ces méthodes sont appelées par le moteur d'essai. Les règles spécifiques qui doivent être suivies lors de la création des classes de test seront décrite en détail plus tard.

Métadonnées contient les attributs nécessaires pour décorer une classe de test, donc il peut être reconnu comme une application de test. Le moteur de Test recherche ces attributs lors du chargement des tests dans le référentiel de Test.

Le contexte de Test représente un ensemble de classes qui donnent accès à l'information de DUREE au cours des différentes phases de l'exécution de tests. Par exemple, vous pouvez utiliser ces classes pour accéder aux différents aspects d'un paquet à l'épreuve, comme les variables, propriétés, contraintes précédentes, les gestionnaires de connexions, en cours d'exécution de tâche, erreurs de paquet et ainsi de suite.

Le moteur de Test désigne les classes de base et les interfaces de l'API SSISTester qui utilisent directement le runtime managé de SSIS. Ils sont utilisés pour charger des packages et classes d'essai dans leurs référentiels respectifs, aussi bien quant à l'exécution de tests et de créer des résultats des tests.

Mini ETL

Pour créer des packages et les classes de test, je vais utiliser Visual Studio 2012 et SQL Server 2012 et j'utiliserai trois paquets pour illustrer un scénario ETL simple dans quel client données, envoyées sous forme de fichier texte sont transformées et stockées dans une base de données. Les paquets sont CopyCustomers.dtsx, LoadCustomers.dtsx et Main.dtsx. CopyCustomers.dtsx copie le fichier Customers.txt d'un endroit à l'autre et sur la façon dont il convertit tous les noms des clients de texte en majuscules. Customers.txt est un simple fichier CSV qui contient les ID et les noms de clients, comme suit :

id,name
1,company1
5,company2
11,company3

LoadCustomers.dtsx charge les noms de convertis la base de données démo. Avant il charge les données dans une table cible appelée Customers­mise en scène, il tronque toutes les données précédemment stockées. À la fin du processus, il stocke le nombre de clients dans une variable. Voici le script pour créer la base de données de démonstration et de la table CustomersStaging :

CREATE
DATABASE [Demo]
GO
USE [Demo]
GO
CREATE TABLE [dbo].[CustomersStaging](
  [Id] [int] NULL,
  [Name] [nvarchar](255) NULL
) ON [PRIMARY]
GO

Le Main.dtsx contient deux tâches d'exécution de Package qui exécutent les éléments CopyCustomers.dtsx et charge­Customers.dtsx, respectivement. Les gestionnaires de connexions à la fois CopyCustomers.dtsx et LoadCustomers.dtsx sont configurés à l'aide des expressions et des variables de package. Les mêmes variables de package sont extraites de la configuration de package parent lorsque exécuté dans un autre package.

Création de tests unitaires

Pour commencer, créez un projet de console et ajoutez des références d'assembly à SSIS.Test.dll et SSIS.Test.Report.dll. Je vais tout d'abord créer un test unitaire pour le paquet de CopyCustomers.dtsx. La figure 2 montre le flux de contrôle (à gauche) et le flux de données (à droite) pour CopyCustomers.dtsx.


Figure 2 contrôle débit (à gauche) et des flux de données (à droite) du Package CopyCustomers.dtsx

Chaque test unitaire est implémenté dans une classe simple qui dérive de la classe BaseUnitTest et doit être décorée avec l'attribut UnitTest :

[UnitTest("CUSTOMERS", "CopyCustomers.dtsx")]
public class CopyCustomersTest : BaseUnitTest{
  protected override void Setup(SetupContext context){}
  protected override void Verify(VerificationContext context){}
  protected override void Teardown(TeardownContext context){}
}

Les marques d'attribut UnitTest une classe en tant qu'unité d'essai mise en oeuvre donc il peut être trouvé par le moteur d'essai. Le premier paramètre correspond au référentiel paquet où un paquet de cible sera chargé pendant l'exécution du test, les visiteurs dans cet exemple. Le deuxième paramètre peut être le nom d'un paquet de cible, le chemin d'accès à une tâche dans le flux de contrôle, le chemin d'accès à un gestionnaire d'événements ou le chemin d'accès à une contrainte précédente. Dans cet exemple, c'est le nom du package CopyCustomers.dtsx parce que je veux tester l'ensemble du paquet. Fondamentalement, l'attribut UnitTest indique au moteur de Test pour rechercher le paquet de CopyCustomers.dtsx dans le référentiel de clients et l'exécuter lors de l'essai de CopyCustomersTest.

BaseUnitTest que toutes les implémentations de test d'unité doivent dériver de la classe de base contient trois méthodes qui doivent être mises en œuvre : Configurer, vérifier et le démontage.

Ces trois méthodes sont exécutées au cours des phases d'essais différents. La méthode d'installation s'exécute avant un paquet de la cible est exécuté par le moteur de Test. Le programme d'installation prépare le paquet et toutes les entrées et les sorties que le paquet dépend donc peut être validé et exécuté avec succès. Dans l'exemple suivant, j'ai mis des chemins pour les variables de package qui sont utilisés comme des chaînes de connexion dans les gestionnaires de connexions :

protected override void Setup(SetupContext context){
  if(File.Exists(@"C:\TestFiles\Archive\Customers.txt"))
    File.Delete(@"C:\TestFiles\Archive\Customers.txt");
  if(File.Exists(@"C:\TestFiles\Converted\Customers.txt"))
    File.Delete(@"C:\TestFiles\Converted\Customers.txt");
  DtsVariable sourceFile = context.Package.GetVariable("SourcePath");
  sourceFile.SetValue(@"\\nc1\Customers\Customers.txt");
  DtsVariable destinationFile = 
    context.Package.GetVariable("DestinationPath");
  destinationFile.SetValue(@"C:\TestFiles\Archive\Customers.txt");
  DtsVariable convertedFile = 
    context.Package.GetVariable("ConvertDestinationPath");
  convertedFile.SetValue(@"C:\TestFiles\Converted\Customers.txt");
}

Après que la méthode d'installation a été exécuté avec succès, le moteur de Test exécute le package de cible. Lorsque le package est exécuté, le moteur de Test appelle la méthode Verify et je peux vérifier si mes affirmations sont vraies :

protected override void Verify(VerificationContext context){
  Assert.AreEqual(true, 
    context.Package.IsExecutionSuccess);
  Assert.AreEqual(true, 
    File.Exists(@"C:\TestFiles\Archive\Customers.txt"));
  Assert.AreEqual(true, 
    File.Exists(@"C:\TestFiles\Converted\Customers.txt"));
  string[] lines = 
    File.ReadAllLines(@"C:\TestFiles\Converted\Customers.txt");
  Assert.AreEqual("COMPANY2", lines[2].Split(',')[1]);
}

La première instruction assert vérifie si le package est exécuté avec succès. L'autre détermine si la tâche de système de fichier FST copie Source fichier copié le fichier \\nc1\Customers\Customers.txt dans le dossier C:\TestFiles\Archive\. Les deux derniers affirme vérifie si les données de noms des clients de convertir DFT flow dénominations sociales tâche correctement converti en majuscules. Plus tôt, j'ai décrit brièvement le contexte de test. Ici vous pouvez voir comment j'ai utilisé le paramètre de contexte pour accéder à un objet de paquet dans les méthodes d'installation et de vérifier.

À la fin du test, j'utilise la méthode de démontage pour supprimer les fichiers qui ont été copiés ou créés par le package :

protected override void Teardown(TeardownContext context){
  File.Delete(@"C:\TestFiles\Archive\Customers.txt");
  File.Delete(@"C:\TestFiles\Converted\Customers.txt");
}

Tests de tâches de flux de contrôle

Les tests peuvent cibler des tâches spécifiques dans le flux de contrôle aussi bien. Par exemple, pour tester le flux de données de clients de charge DFT dans le package LoadCustomers.dtsx, j'ai utilisé un paramètre supplémentaire de l'attribut UnitTest, appelé ExecutableName, pour indiquer au moteur de Test que je veux tester cette tâche :

[UnitTest("CUSTOMERS", "LoadCustomers.dtsx",ExecutableName =
  @"

!SEQC Load]

!LoadCustomers]

!CopyCustomers]")]   public void TestWholePackage(ActionContext context){     Assert.AreEqual(true, context.Package.IsExecutionSuccess);   }   [ActionMethod(@"

!FST Copy Source File]")]   public void TestCopySourceFile(ActionContext context){     Assert.AreEqual(true, context.ActiveExecutable.IsExecutionSuccess);     Assert.AreEqual(true, File.Exists(@"C:\TestFiles\Archive\Customers.txt"));   }   [ActionMethod(@"

!DFT Convert customer names]")]   public void TestConvertCustomersNames(ActionContext context){     Assert.AreEqual(true, context.ActiveExecutable.IsExecutionSuccess);     string[] lines = File.ReadAllLines(@"C:\TestFiles\Converted\Customers.txt");     Assert.AreEqual("COMPANY2", lines[2].Split(‘,’)[1]);   } }

Chaque classe de test en direct doit dériver de la classe BaseLiveTest, une différence majeure par rapport à un test unitaire. La classe BaseLiveTest est utilisée en interne par le moteur de Test pour exécuter des tests direct et possède pas de méthodes qui doivent être remplacées. L'attribut ActionClass marque cette classe comme un test en direct. Les paramètres sont les mêmes que lorsque vous utilisez l'attribut UnitTest — paquet de référentiel et de la cible. Notez que contrairement aux tests unitaires où chaque test est implémentée dans une classe unique, distincte, qu'une seule classe est nécessaire pour mettre en œuvre tous les post-conditions pour un package. Les classes de test en direct peuvent avoir un nombre arbitraire de post-conditions qui devrait être évaluée. Ces post-conditions correspondent à la méthode Verify dans un test unitaire et sont implémentées comme des méthodes décorées avec l'attribut ActionMethod. Dans l'exemple de Figure 8, j'ai une post-condition pour chaque tâche dans le package et l'autre pour l'emballage proprement dit. ActionMethod accepte un chemin vers la tâche de la cible, qui est le même que le ExecutableName dans l'attribut UnitTest. Cela indique au moteur de Test pour exécuter cette méthode lorsque la tâche de la cible est exécutée. Contrairement à la méthode Verify, qui est toujours exécutée, ces post-conditions ne peuvent pas être appelées lorsque, par exemple, la tâche cible n'exécute pas correctement, ou la contrainte précédente a la valeur false. Le paramètre ActionContext fournit la même fonctionnalité que la VerificationContext.

L'exécution des Tests Live

Les étapes nécessaires pour exécuter des tests direct sont légèrement différentes que lors de l'exécution de tests unitaires. Pour exécuter des tests direct, remplacez la méthode Main dans le fichier Program.cs par le code dans Figure 9.

Figure 9 la méthode principale pour l'exécution des Tests Live

static void Main{
  string dbConStr = @"Data Source=.;Integrated Security=SSPI;Initial Catalog=Demo";
  string ssisConStr = @"Provider=SQLNCLI11;" + dbConStr;
  ILiveTestEngine engine = 
    EngineFactory.GetClassInstance<ILiveTestEngine>();
  engine.LoadPackages("CUSTOMERS", @"C:\TargetPackages\");
  engine.LoadActions();
  ExecutionParameters params = new ExecutionParameters();
  params.AddVariable(@"

!Main].[CopyCustomersPath]", @"C:\TargetPackages\CopyCustomers.dtsx");   params.AddVariable(@"

!Main].[ConvertDestinationPath]",     @"C:\TestFiles\Converted\Customers.txt");   params.AddVariable(@"

!Main].[SourcePath]", @"\\nc1\Customers\Customers.txt");   engine.SetExecutionParameters(parameters);   engine.ExecuteLiveTestsWithGui("CUSTOMERS", "Main.dtsx"); }

J'ai besoin d'une instance de ILiveTestEngine, que je crée à l'aide de EngineFactory. Chargement des packages, c'est le même que lors de l'utilisation de IUnitTestEngine. La méthode de LoadActions charge de toutes les actions définies dans l'assembly appelant et est pratiquement l'équivalent de charge­UnitTests. À ce stade, cependant, la similitude avec l'unité teste s'arrête. Au lieu d'exécuter des tests unitaires, je dis le moteur de Test pour exécuter le package de Main.dtsx en appelant le ExecuteLiveTestsWithGui.

Lorsque le package Main.dtsx démarre, il fonctionne le CopyCustomers.dtsx par l'exécution de la tâche CopyCustomers de l'EPT. Chacun terminé avec succès tâche dans les déclencheurs de CopyCustomers.dtsx une des méthodes d'action correspondante dans la classe CopyCustomersLiveTests. Il est important de noter que ce test a implicitement vérifie les paramètres de configuration du package CopyCustomers.dtsx.

Variables configurées héritent leurs valeurs le paquet Main.dtsx. Veuillez noter que ces variables sont utilisées comme des chaînes de connexion dans les gestionnaires de connexions de fichiers plats du package CopyCustomers.dtsx. Cela signifie essentiellement que des succès de l'exécution des tâches dans le paquet de CopyCustomers.dtsx dépend de savoir si le transfert de valeur entre ces deux paquets fonctionne correctement. Il s'agit d'un exemple simple de comment les interactions et les dépendances entre paquets sont testés, mais vous pouvez imaginer des scénarios plus complexes, où des tests unitaires isolé ne serait pas suffisant pour couvrir le cas de test.

Test moteur Internals

La classe de base implémentant les principales fonctions de la bibliothèque SSISTester est TestEngine. C'est une classe interne qui est exposée via les interfaces IUnitTestEngine et ILiveTestEngine. Les deux méthodes qui révèlent la plupart de la logique interne sont LoadUnitTests (montré dans Figure 10) et ExecuteUnitTests.

Figure 10 la méthode de LoadUnitTests

public void LoadUnitTests(){
  Assembly assembly = Assembly.GetCallingAssembly();
  IEnumerable<Type> types = assembly.GetTypes().Where(t => t.GetCustomAttributes(false).OfType<UnitTestAttribute>().Any() && 
    t.BaseType != null && t.BaseType.Name.Equals("BaseUnitTest"));
  foreach (Type t in types)
  {
    var attribute =
      t.GetCustomAttributes(false).OfType<UnitTestAttribute>().Single();
    DtsPackage package =
      _packages[attribute.Repository].GetForName(attribute.PackageName);
    string executable = attribute.ExecutableName;
    bool precedenceTestOnly = attribute.PrecedenceConstraintsTestOnly;
    var test = (BaseUnitTest)Activator.CreateInstance(t);
    test.TestClass = t;
    test.SetTestTargets(package, executable, precedenceTestOnly);
    test.Started += BaseUnitTestStarted;
    test.Finished += BaseUnitTestFinished;
    _unitTests.Add(test);
  }
}

LoadUnitTests itère fondamentalement toutes les classes décorées avec l'attribut UnitTest et crée une instance de chacun. Ces instances sont alors castées en BaseUnitTest et sont assignés le package cible précédemment chargé depuis le dépôt de paquets. À la fin, toutes les instances sont enregistrés dans la liste de _unitTests. La méthode ExecuteUnitTests itère toutes les instances de BaseUnitTest et appelle ExecuteTests sur chacune :

public void ExecuteUnitTests(){
  foreach (BaseUnitTest t in _unitTests){
    t.ExecuteTest();
  }
}

L'exécution de tests unitaires est implémentée dans la méthode ExecuteTest (montré dans Figure 11) dans la classe BaseUnitTest.

Figure 11 la ExecuteTest, méthode

public void ExecutTest(){
  Result = new UnitTestResult(Package, Executable) { TestOutcome =
    TestOutcome.InProgress, StartedAt = DateTime.Now };
  ExecuteSetup(CreateSetupContext());
  if (!Result.IsSetupSuccess)
    ExecuteTeardown(CreateTeardownContext());
  else{
    if(!PrecedenceOnly)
      Executable.Execute();
    ExecuteVerify(CreateVerifyContext());
    ExecuteTeardown(CreateTeardownContext());
    Result.FinishedAt = DateTime.Now;
  }
}

L'aspect le plus important de cette méthode est qu'elle exécute les méthodes d'installation, de vérifier et de destruction, mais aussi l'ensemble de la cible.

Leave a Reply

Post Navigation