web-dev-qa-db-fra.com

Paramètre de passage C # NUnit TestCaseSource

J'ai la méthode suivante qui génère un ensemble de cas de test!

public IEnumerable<ResultsOfCallMyMethod> PrepareTestCases(param1)
{
    foreach (string entry in entries)
    {
        yield return callMyMethod(param1);
    }
}

Comment puis-je transmettre un paramètre de type chaîne en tant que paramètre à ma méthode PrepareTestCases()?

Existe-t-il un moyen de procéder comme suit:

[Test, Category("Integration"), TestCaseSource("PrepareTestCases", param1)]
public void TestRun(ResultsOfCallMyMethod testData)
{
    // do something!
}
14
sparkr

Si vous regardez Doc TestCaseSourceAttribute vous verrez qu'il n'y a aucun moyen de passer le paramètre à la méthode qui retourne les cas de test.

La méthode, qui génère des cas de test, doit être sans paramètre .

Donc, en supposant que vous allez éviter la duplication de code et que vous devez réutiliser la même méthode pour générer quelques listes de cas de test, je vous recommande de faire ce qui suit:

  1. Écrire une méthode paramétrée qui génère réellement des ensembles de cas de test:
    (PrepareTestCases() le fait déjà)

    public IEnumerable<ResultsOfCallMyMethod> PrepareTestCases(string param)
    {
        foreach (string entry in entries)
        {
            yield return CallMyMethod(param);
        }
    }
    
  2. Écrivez des wrappers sans paramètres qui appellent le générateur de cas de test et passez le paramètre souhaité à cet endroit:

    public IEnumerable<ResultsOfCallMyMethod> PrepareTestCases_Param1()
    {
        return PrepareTestCases("param1");
    }
    
    public IEnumerable<ResultsOfCallMyMethod> PrepareTestCases_Param2()
    {
        return PrepareTestCases("param2");
    }
    
  3. Écrivez des méthodes de test et passez des wrappers sans paramètre comme sources de cas de test:

    [TestCaseSource("PrepareTestCases_Param1")]
    public void TestRun1(ResultsOfCallMyMethod data)
    {
    }
    
    [TestCaseSource("PrepareTestCases_Param2")]
    public void TestRun2(ResultsOfCallMyMethod data)
    {
    }
    
10
Alexander Stepaniuk

J'ai fait un changement pour cela dans la dernière version de nunit qui est sur le point de sortir (3.2).

https://github.com/nunit/nunit/blob/4f54fd7e86f659682e7a538dfe5abee0c33aa8b4/CHANGES.txt

  • TestCaseSourceAttribute prend désormais facultativement un tableau de paramètres qui peuvent être passés à la méthode source

Il est maintenant possible de faire quelque chose comme ça

[Test, Category("Integration"), TestCaseSource(typeof(MyDataSources),"PrepareTestCases", new object[] {param1})]
public void TestRun(ResultsOfCallMyMethod testData)
{
// do something!
}

private class MyDataSources
{
  public IEnumerable<ResultsOfCallMyMethod> PrepareTestCases(param1)
  {
    foreach (string entry in entries)
    {
        yield return callMyMethod(param1);
    }
  }
}
21
Joe

Dans mon cas, je voudrais charger des données à partir d'un fichier CSV mais je n'ai pas pu transmettre le nom de fichier à la "source de données". Après avoir lutté un peu, j'arrive à cette solution à deux cents.

Au début, j'ai hérité de TestCaseSourceAttirbute

/// <summary>
/// FactoryAttribute indicates the source to be used to provide test cases for a test method.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class TestCaseCsvAttribute : TestCaseSourceAttribute 
{
    public TestCaseCsvAttribute(Type mapped, Type config) : base(typeof(TestCsvReader<,>).MakeGenericType(mapped, config), "Data")
    { }
}

puis j'ai créé la couche de données, dans mon cas un lecteur CSV.

    /// <summary>
    /// Test data provider
    /// </summary>
    /// <typeparam name="T">Type to return in enumerable</typeparam>
    /// <typeparam name="C">Configuration type that provide Filenames</typeparam>
    public sealed class TestCsvReader<T, C>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="TestCsvReader{T, C}"/> class.
        /// </summary>
        public TestCsvReader()
        {
            this.Config = (C)Activator.CreateInstance<C>();
        }

        /// <summary>
        /// Gets or sets the configuration.
        /// </summary>
        /// <value>
        /// The configuration.
        /// </value>
        private C Config { get; set; }

        /// <summary>
        /// Gets the filename.
        /// </summary>
        /// <value>
        /// The filename.
        /// </value>
        /// <exception cref="System.Exception">
        /// </exception>
        private string Filename
        {
            get
            {
                try
                {
                    string result = Convert.ToString(typeof(C).GetProperty(string.Format("{0}Filename", typeof(T).Name)).GetValue(this.Config));
                    if (!File.Exists(result))
                        throw new Exception(string.Format("Unable to find file '{0}' specified in property '{1}Filename' in class '{1}'", result, typeof(C).Name));

                    return result;
                }
                catch
                {
                    throw new Exception(string.Format("Unable to find property '{0}Filename' in class '{1}'", typeof(T).Name, typeof(C).Name));
                }
            }
        }

        /// <summary>
        /// Yields values from source
        /// </summary>
        /// <returns></returns>
        public IEnumerable Data()
        {
            string file = this.Filename;

            T[] result = null;
            using (StreamReader reader = File.OpenText(file))
            {
                //TODO: do it here your magic
            }
            yield return new TestCaseData(result);
        }
}

Ensuite, j'ai créé une classe avec la seule portée pour contenir des propriétés avec les chemins de fichier. Il y a une convention de nom sur la propriété, c'est ClassTypeName + "Filename".

public class Configurations
{
    public string ConflictDataFilename
    {
        get
        {
            return @"C:\test.csv";
        }
    }
}

À ce stade, décorez en conséquence le test, avec le type de classe à mapper aux données et la classe qui contient le chemin du fichier.

[Test(Description="Try this one")]
[TestCaseCsv(typeof(ClassMappedToData), typeof(Configurations))]
public void Infinite(ClassMappedToData[] data)
{
}

J'espère que cela peut aider un peu.

1
Andrea Celin