2015-02-19 7 views
10

Ho il seguente metodo che genera un set di casi di test!C# NUnit TestCaseSource Passing Parameter

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

Come posso passare param che è di tipo stringa come parametro per il mio metodo PrepareTestCases()?

C'è un modo per effettuare le seguenti operazioni:

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

http://stackoverflow.com/questions/8869734/how-to-use-testcase-in-nunit-2-5 –

+2

Non è quello che stavo cercando! – sparkr

risposta

10

Se si guarda al TestCaseSourceAttribute doc si vedrà non c'è alcun modo per passare il parametro per il metodo che restituisce casi di test.

Il metodo, che genera casi di test, deve essere senza parametro.

Quindi, supponendo che si sta andando al fine di evitare la duplicazione del codice ed è necessario riutilizzare lo stesso metodo per generare alcune liste di casi di test, vi consiglio di fare quanto segue:

  1. Scrivi metodo parametrizzato che genera effettivamente casi di test insiemi:
    (PrepareTestCases() fa già quello) involucri

    public IEnumerable<ResultsOfCallMyMethod> PrepareTestCases(string param) 
    { 
        foreach (string entry in entries) 
        { 
         yield return CallMyMethod(param); 
        } 
    } 
    
  2. scrittura senza parametri che richiedono generatore casi di test e passano Parame desiderato ter c'è:

    public IEnumerable<ResultsOfCallMyMethod> PrepareTestCases_Param1() 
    { 
        return PrepareTestCases("param1"); 
    } 
    
    public IEnumerable<ResultsOfCallMyMethod> PrepareTestCases_Param2() 
    { 
        return PrepareTestCases("param2"); 
    } 
    
  3. metodi di scrittura di prova e le involucri paremeterless lì come fonti di casi di test:

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

Nel mio caso vorrei caricare dati da un file CSV, ma non potevo passare il nome del file alla "fonte dati". Dopo aver faticato un po ', vengo a questa soluzione da due soldi.

In un primo momento ho ereditato TestCaseSourceAttirbute

Poi ho creato lo strato di dati, nel mio caso un lettore 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); 
     } 
} 

Quindi ho creato una classe con l'unico ambito per contenere le proprietà con i percorsi dei file. C'è una convenzione sul nome della proprietà, che è ClassTypeName + "Filename".

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

A questo punto basta decorare di conseguenza il test, con il tipo di classe per mappare i dati e la classe che contiene il percorso del file.

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

Spero che questo può aiutare un po '.

14

Ho apportato una modifica per questo nell'ultima versione di nunit che sta per essere rilasciata (3.2).

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

  • TestCaseSourceAttribute ora prende opzionalmente un array di parametri che può essere passato al metodo sorgente

È ora possibile fare qualcosa di simile

[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); 
    } 
    } 
} 
+0

Ho ricevuto un errore di compilazione per questo: Errore \t CS0182: \t Un argomento di attributo deve essere un'espressione costante, tipo di espressione o espressione di creazione di matrice di un tipo di parametro di attributo. Cosa mi manca? –

+0

Non importa. L'ho capito: l'oggetto [] deve essere scritto in modo esplicito. Btw nameof() consentito anche nonostante il messaggio di errore –