Génération de testsTest generation

Dans les tests unitaires traditionnels, un test se compose de plusieurs choses :In traditional unit testing, a test consists of several things:

Voici un exemple de structure de test :Following is an example test structure:

[Test]
void MyTest() {
    // data
    ArrayList a = new ArrayList();

    // method sequence
    a.Add(5);

    // assertions
    Assert.IsTrue(a.Count==1);
    Assert.AreEqual(a[0], 5);
}

IntelliTest peut souvent déterminer automatiquement les valeurs appropriées des arguments pour des tests unitaires paramétrables plus généraux, qui fournissent la séquence des appels de méthode et des assertions.IntelliTest can often automatically determine relevant argument values for more general Parameterized Unit Tests, which provide the sequence of method calls and assertions.

Générateurs de testsTest generators

IntelliTest génère des cas de test en sélectionnant une séquence de méthodes de l’implémentation testée à exécuter, puis en générant les entrées pour les méthodes en vérifiant les assertions sur les données dérivées.IntelliTest generates test cases by selecting a sequence of methods of the implementation under test to execute, and then generating inputs for the methods while checking assertions over the derived data.

Un test unitaire paramétrable déclare directement une séquence d’appels de méthode dans son corps.A parameterized unit test directly states a sequence of method calls in its body.

Quand IntelliTest doit construire des objets, des appels aux constructeurs et aux méthodes de fabrique sont ajoutés automatiquement à la séquence en fonction des besoins.When IntelliTest needs to construct objects, calls to constructors and factory methods will be added automatically to the sequence as required.

Tests unitaires paramétrablesParameterized unit testing

Les tests unitaires paramétrables sont des tests qui prennent des paramètres.Parameterized Unit Tests (PUTs) are tests that take parameters. Contrairement aux tests unitaires traditionnels, qui sont généralement des méthodes fermées, les tests unitaires paramétrables prennent n’importe quel ensemble de paramètres.Unlike traditional unit tests, which are usually closed methods, PUTs take any set of parameters. C’est aussi simple que ça ?Is it that simple? Oui. À partir de là, IntelliTest va essayer de générer l’ensemble (minimal) des entrées qui couvrent entièrement le code accessible à partir du test.Yes - from there, IntelliTest will try to generate the (minimal) set of inputs that fully cover the code reachable from the test.

Les tests unitaires paramétrables sont définis à l’aide de l’attribut personnalisé PexMethod, d’une façon similaire à MSTest (ou NUnit ou xUnit).PUTs are defined using the PexMethod custom attribute in a similar fashion to MSTest (or NUnit, xUnit). Les tests unitaires paramétrables sont regroupés logiquement dans des classes marquées avec PexClass.PUTs are instance methods logically grouped in classes tagged with PexClass. L’exemple suivant montre un test unitaire paramétrable simple stocké dans la classe MyPexTest :The following example shows a simple PUT stored in the MyPexTest class:

[PexMethod]
void ReplaceFirstChar(string target, char c) {

    string result = StringHelper.ReplaceFirstChar(target, c);

    Assert.AreEqual(result[0], c);
}

ReplaceFirstChar est une méthode qui remplace le premier caractère d’une chaîne :where ReplaceFirstChar is a method that replaces the first character of a string:

class StringHelper {
    static string ReplaceFirstChar(string target, char c) {
        if (target == null) throw new ArgumentNullException();
        if (target.Length == 0) throw new ArgumentOutOfRangeException();
        return c + target.Substring(1);
    }
}

À partir de ce test, IntelliTest peut automatiquement générer des entrées pour un test unitaire paramétrable qui couvre de nombreux chemins d’exécution du code testé.From this test, IntelliTest can automatically generate inputs for a PUT that covers many execution paths of the tested code. Chaque entrée couvrant un chemin d’exécution différent est « sérialisé » sous forme de test unitaire :Each input that covers a different execution path gets "serialized" as a unit test:

[TestMethod, ExpectedException(typeof(ArgumentNullException))]
void ReplaceFirstChar0() {
    this.ReplaceFirstChar(null, 0);
}
...
[TestMethod]
void ReplaceFirstChar10() {
    this.ReplaceFirstChar("a", 'c');
}

Tests unitaires paramétrables génériquesGeneric parameterized unit testing

Les tests unitaires paramétrables peuvent être des méthodes génériques.Parameterized unit tests can be generic methods. Dans ce cas, l’utilisateur doit spécifier les types utilisés pour instancier la méthode en utilisant PexGenericArguments.In this case, the user must specify the types used to instantiate the method by using PexGenericArguments.

[PexClass]
public partial class ListTest {
    [PexMethod]
    [PexGenericArguments(typeof(int))]
    [PexGenericArguments(typeof(object))]
    public void AddItem<T>(List<T> list, T value)
    { ... }
}

Autorisation des exceptionsAllowing exceptions

IntelliTest fournit de nombreux attributs de validation pour aider au triage des exceptions en exceptions attendues et en exceptions inattendues.IntelliTest provides numerous validation attributes to help triage exceptions into expected exceptions and unexpected exceptions.

Les exceptions attendues génèrent des cas de test négatifs avec l’annotation appropriée, par exemple ExpectedException(typeof(xxx)), alors que les exceptions inattendues génèrent des cas de test non réussis.Expected exceptions generate negative test cases with the appropriate annotation such as ExpectedException(typeof(xxx)), while unexpected exceptions generate failing test cases.

[PexMethod, PexAllowedException(typeof(ArgumentNullException))]
void SomeTest() {...}

Les validateurs sont :The validators are:

Test de types internesTesting internal types

IntelliTest peut « tester » des types internes dès lors qu’il peut les voir.IntelliTest can "test" internal types, as long as it can see them. Pour qu’IntelliTest voie les types, l’attribut suivant est ajouté à votre produit ou votre projet de test par les Assistants IntelliTest de Visual Studio :For IntelliTest to see the types, the following attribute is added to your product or test project by the Visual Studio IntelliTest wizards:

[assembly: InternalsVisibleTo("Microsoft.Pex, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293

Hypothèses et assertionsAssumptions and assertions

Les utilisateurs peuvent utiliser des hypothèses et des assertions pour exprimer des conditions préalables (hypothèses) et des post-conditions (assertions) sur leurs tests.Users can use assumptions and assertions to express preconditions (assumptions) and postconditions (assertions) about their tests. Quand IntelliTest génère un ensemble de valeurs de paramètre et « explore » le code, il peut ne pas respecter une hypothèse du test.When IntelliTest generates a set of parameter values and "explores" the code, it might violate an assumption of the test. Quand cela se produit, il ne génère pas de test pour ce chemin mais l’ignore sans rien indiquer.When that happens, it will not generate a test for that path but will silently ignore it.

Les assertions sont un concept bien connu dans les frameworks de tests unitaires standard : IntelliTest « comprend » donc déjà les classes Assert prédéfinies fournies par chaque framework de test pris en charge.Assertions are a well known concept in regular unit test frameworks, so IntelliTest already "understands" the built-in Assert classes provided by each supported test framework. Cependant, la plupart des frameworks ne fournissent pas de classe Assume.However, most frameworks do not provide an Assume class. Dans ce cas, IntelliTest fournit la classe PexAssume.In that case, IntelliTest provides the PexAssume class. Si vous ne voulez pas utiliser un framework de tests, IntelliTest a également la classe PexAssert.If you do not want to use an existing test framework, IntelliTest also has the PexAssert class.

[PexMethod]
public void Test1(object o) {
    // precondition: o should not be null
    PexAssume.IsNotNull(o);

    ...
}

En particulier, l’hypothèse de non-égalité à Null peut être encodée comme attribut personnalisé :In particular, the non-nullness assumption can be encoded as a custom attribute:

[PexMethod]
public void Test2([PexAssumeNotNull] object o)
// precondition: o should not be null
{
   ...
}

Condition préalablePrecondition

Une condition préalable d’une méthode exprime les conditions sous lesquelles la méthode réussit.A precondition of a method expresses the conditions under which the method will succeed.

En règle générale, la condition préalable est appliquée en vérifiant les paramètres et l’état de l’objet, et en levant une ArgumentException ou une InvalidOperationException si elle n’est pas respectée.Usually, the precondition is enforced by checking the parameters and the object state, and throwing an ArgumentException or InvalidOperationException if it is violated.

Dans IntelliTest, une condition préalable d’un test unitaire paramétrable est exprimée avec PexAssume.In IntelliTest, a precondition of a parameterized unit test is expressed with PexAssume.

Post-conditionPostcondition

Une post-condition d’une méthode exprime les conditions qui doivent être satisfaites pendant et après l’exécution de la méthode, en supposant que ses conditions préalables étaient initialement valides.A postcondition of a method expresses the conditions which should hold during and after execution of the method, assuming that its preconditions were initially valid.

En règle générale, la post-condition est appliquée par des appels à des méthodes Assert.Usually, the postcondition is enforced by calls to Assert methods.

Avec IntelliTest, une post-condition d’un test unitaire paramétrable est exprimée avec PexAssert.With IntelliTest, a postcondition of a parameterized unit test is expressed with PexAssert.

Échecs des testsTest failures

Quand un cas de test généré échoue-t-il ?When does a generated test case fail?

  1. S’il ne se termine pas dans les limites configurées pour le chemin , il est considéré comme ayant échoué, sauf si l’option TestExcludePathBoundsExceeded est définie.If it does not terminate within the configured path bounds, it is considered as a failure unless the TestExcludePathBoundsExceeded option is set

  2. Si le test lève une PexAssumeFailedException, il réussit.If the test throws a PexAssumeFailedException, it succeeds. Cependant, il est généralement éliminé, sauf si TestEmissionFilter est défini sur All.However, it is usually filtered out unless TestEmissionFilter is set to All

  3. Si le test ne respecte pas une assertion, par exemple en levant une exception de violation d’assertion d’un framework de tests unitaires, il échoue.If the test violates an assertion; for example, by throwing an assertion violation exception of a unit testing framework, it fails

Si aucune des situations ci-dessus ne génère une décision, un test réussit si et seulement si il ne lève pas d’exception.If none of the above produce a decision, a test succeeds if and only if it does not throw an exception. Les violations d’assertion sont traitées de la même façon que les exceptions.Assertion violations are treated in the same way as exceptions.

Installation et destructionSetup and tear down

Dans le cadre de l’intégration à des frameworks de tests, IntelliTest prend en charge la détection et l’exécution de méthodes d’installation et destruction.As part of the integration with test frameworks, IntelliTest supports detecting and running setup and tear down methods.

ExempleExample

using Microsoft.Pex.Framework;
using NUnit.Framework;

namespace MyTests
{
    [PexClass]
    [TestFixture]
    public partial class MyTestClass
    {
        [SetUp]
        public void Init()
        {
            // monitored
        }

        [PexMethod]
        public void MyTest(int i)
        {
        }

        [TearDown]
        public void Dispose()
        {
            // monitored
        }
    }
}

Informations supplémentairesFurther reading

Vous avez des commentaires ?Got feedback?

Postez vos idées et demandes de fonctionnalités sur UserVoice.Post your ideas and feature requests on UserVoice.