Domanda

Mi chiedo come usare NUnit correttamente. Per prima cosa ho creato un progetto di test separato che utilizza il mio progetto principale come riferimento. Ma in quel caso non sono in grado di testare metodi privati. Immagino che dovessi includere il mio testcode nel mio codice principale ?! - Questo non sembra essere il modo corretto di farlo. (Non mi piace l'idea del codice di spedizione con test al suo interno.)

Come testare metodi privati ??con NUnit?

È stato utile?

Soluzione

Generalmente, i test unitari si rivolgono all'interfaccia pubblica di una classe, in base alla teoria che l'implementazione è irrilevante, purché i risultati siano corretti dal punto di vista del cliente.

Quindi, NUnit non fornisce alcun meccanismo per testare membri non pubblici.

Altri suggerimenti

Anche se concordo sul fatto che l'obiettivo del test unitario dovrebbe essere l'interfaccia pubblica, si ottiene un'impressione molto più granulare del codice se si verificano anche metodi privati. Il framework di test MS consente questo tramite l'uso di PrivateObject e PrivateType, mentre NUnit no. Quello che faccio invece è:

private MethodInfo GetMethod(string methodName)
{
    if (string.IsNullOrWhiteSpace(methodName))
        Assert.Fail("methodName cannot be null or whitespace");

    var method = this.objectUnderTest.GetType()
        .GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);

    if (method == null)
        Assert.Fail(string.Format("{0} method not found", methodName));

    return method;
}

In questo modo significa che non è necessario compromettere l'incapsulamento a favore della testabilità. Tieni presente che dovrai modificare i tuoi BindingFlags se desideri testare metodi statici privati. L'esempio sopra è solo per esempio metodi.

Un modello comune per scrivere unit test è testare solo metodi pubblici.

Se scopri di avere molti metodi privati ??che vuoi testare, normalmente questo è un segno che dovresti refactificare il tuo codice.

Sarebbe sbagliato rendere pubblici questi metodi sulla classe in cui vivono attualmente. Ciò romperebbe il contratto che desideri che quella classe abbia.

Potrebbe essere corretto spostarli in una classe di supporto e renderli pubblici lì. Questa classe potrebbe non essere esposta dalla tua API.

In questo modo il codice di test non viene mai mischiato con il tuo codice pubblico.

Un problema simile è il test di classi private, ad es. classi che non esporti dal tuo assembly. In questo caso è possibile rendere esplicitamente l'assembly del codice di prova amico dell'assembly del codice di produzione utilizzando l'attributo InternalsVisibleTo.

È possibile testare metodi privati ??dichiarando il proprio assieme di prova come un assieme amico dell'assieme di destinazione che si sta testando. Vedi il link sotto per i dettagli:

http://msdn.microsoft.com/en-us/library/ 0tke9fxk.aspx

Questo può essere utile in quanto separa principalmente il tuo codice di prova dal tuo codice di produzione. Non ho mai usato questo metodo da solo in quanto non ne ho mai trovato bisogno. Suppongo che potresti usarlo per provare e testare casi di test estremi che semplicemente non puoi replicare nel tuo ambiente di test per vedere come il tuo codice lo gestisce.

Come è stato detto, non è necessario testare metodi privati. Più che probabile che tu voglia trasformare il tuo codice in blocchi più piccoli. Un suggerimento che potrebbe esserti utile quando verrai a refactor è cercare di pensare al dominio a cui il tuo sistema si riferisce e pensare agli oggetti "reali" che popolano questo dominio. I tuoi oggetti / classi nel tuo sistema dovrebbero essere direttamente correlati a un oggetto reale che ti permetterà di isolare il comportamento esatto che l'oggetto dovrebbe contenere e limitare anche le responsabilità degli oggetti. Ciò significa che stai eseguendo il refactoring logicamente piuttosto che solo per rendere possibile testare un metodo particolare; sarai in grado di testare il comportamento degli oggetti.

Se senti ancora la necessità di eseguire il test interno, potresti anche prendere in considerazione l'idea di deridere i tuoi test, poiché probabilmente vorrai concentrarti su un pezzo di codice. Il derisione è il punto in cui si inietta una dipendenza degli oggetti, ma gli oggetti iniettati non sono gli oggetti "reali" o di produzione. Sono oggetti fittizi con comportamento codificato per facilitare l'isolamento degli errori comportamentali. Rhino.Mocks è un popolare framework di derisione gratuito che essenzialmente scriverà gli oggetti per te. TypeMock.NET (un prodotto commerciale con un'edizione della comunità disponibile) è un framework più potente in grado di deridere oggetti CLR. Molto utile per deridere le classi SqlConnection / SqlCommand e Datatable, ad esempio durante il test di un'app di database.

Speriamo che questa risposta ti dia un po 'più di informazioni per informarti sul Test unitario in generale e per aiutarti a ottenere risultati migliori dal Test unitario.

Sono a favore della possibilità di testare metodi privati. All'avvio di xUnit era previsto il test della funzionalità dopo la scrittura del codice. Testare l'interfaccia è sufficiente per questo scopo.

Il test unitario si è evoluto fino allo sviluppo guidato dai test. Avere la capacità di testare tutti i metodi è utile per quell'applicazione.

L'obiettivo principale del test unitario è testare i metodi pubblici di una classe. Quei metodi pubblici useranno quei metodi privati. I test unitari metteranno alla prova il comportamento di ciò che è pubblicamente disponibile.

Questa domanda è nei suoi anni avanzati, ma ho pensato di condividere il mio modo di farlo.

Fondamentalmente, ho tutte le mie classi di test unitari nell'assembly che stanno testando in uno spazio dei nomi 'UnitTest' sotto il 'default' per quell'assemblaggio - ogni file di test è racchiuso in un:

#if DEBUG

...test code...

#endif

blocco e tutto ciò significa che a) non viene distribuito in una versione eb) posso usare le dichiarazioni di livello internal / Friend senza saltare il cerchio.

L'altra cosa che offre, più pertinente a questa domanda, è l'uso delle classi parziali , che possono essere usate per creare un proxy per testare metodi privati, quindi ad esempio per testare qualcosa come un metodo privato che restituisce un valore intero:

public partial class TheClassBeingTested
{
    private int TheMethodToBeTested() { return -1; }
}

nelle classi principali dell'assembly e nella classe test:

#if DEBUG

using NUnit.Framework;

public partial class TheClassBeingTested
{
    internal int NUnit_TheMethodToBeTested()
    {
        return TheMethodToBeTested();
    }
}

[TestFixture]
public class ClassTests
{
    [Test]
    public void TestMethod()
    {
        var tc = new TheClassBeingTested();
        Assert.That(tc.NUnit_TheMethodToBeTested(), Is.EqualTo(-1));
    }
}

#endif

Ovviamente, devi assicurarti di non utilizzare questo metodo durante lo sviluppo, anche se una build di Release indicherà presto una chiamata involontaria ad esso, se lo fai.

Ci scusiamo se questo non risponde alla domanda, ma soluzioni come l'uso di reflection, istruzioni #if #endif o rendere visibili metodi privati ??non risolvono il problema. Ci possono essere diversi motivi per non rendere visibili i metodi privati ??... cosa succede se, ad esempio, il codice di produzione e il team sta scrivendo retrospettivamente unit test.

Per il progetto su cui sto lavorando solo MSTest (purtroppo) sembra avere un modo, usando gli accessori, di testare metodi privati.

Non testare le funzioni private. Esistono modi per utilizzare la riflessione per accedere a metodi e proprietà privati. Ma questo non è davvero facile e scoraggio fortemente questa pratica.

Semplicemente non dovresti testare nulla che non sia pubblico.

Se hai alcuni metodi e proprietà interni, dovresti considerare di cambiarlo in pubblico o di spedire i tuoi test con l'app (qualcosa che non vedo davvero come un problema).

Se il tuo cliente è in grado di eseguire una Suite di test e vedere che il codice che hai consegnato in realtà è "funzionante", non vedo questo come un problema (fintanto che non fornisci il tuo IP attraverso Questo). Le cose che includo in ogni versione sono rapporti sui test e rapporti sulla copertura del codice.

Puoi rendere i tuoi metodi protetti interni e quindi utilizzare assembly: InternalVisibleTo (" NAMESPACE ")  al tuo spazio dei nomi di prova.

Quindi, NO! Non è possibile accedere a metodi privati, ma questa è una soluzione alternativa.

In teoria di Unit Testing dovrebbe essere testato solo il contratto. vale a dire solo membri pubblici della classe. Ma in pratica lo sviluppatore di solito vuole testare i membri interni. - e non è male. Sì, va contro la teoria, ma in pratica può essere utile a volte.

Quindi se vuoi davvero testare i membri interni puoi usare uno di questi approcci:

  1. Rendi pubblico il tuo membro. In molti libri gli autori lo suggeriscono approccio semplice
  2. Puoi rendere i membri interni e aggiungere InternalVisibleTo a assebly
  3. Puoi proteggere i membri della classe ed ereditare la tua classe di test dalla tua classe under testing.

Esempio di codice (pseudo codice):

public class SomeClass
{
    protected int SomeMethod() {}
}
[TestFixture]
public class TestClass : SomeClass{

    protected void SomeMethod2() {}
    [Test]
    public void SomeMethodTest() { SomeMethod2(); }
}

Vorrei rendere visibile il pacchetto dei metodi privati. In questo modo lo mantieni ragionevolmente privato pur essendo in grado di testare questi metodi. Non sono d'accordo con le persone che affermano che le interfacce pubbliche sono le uniche che dovrebbero essere testate. C'è spesso un codice veramente critico nei metodi privati ??che non può essere testato correttamente passando solo attraverso le interfacce esterne.

Quindi si riduce davvero a se ti interessa di più sul codice corretto o sulla nascondere le informazioni. Direi che la visibilità del pacchetto è un buon compromesso poiché per accedere a quel metodo qualcuno dovrebbe inserire la propria classe nel pacchetto. Questo dovrebbe davvero farli riflettere due volte se è davvero una cosa intelligente da fare.

Sono un ragazzo Java tra l'altro, quindi il pacchetto visibile potrebbe essere chiamato qualcosa di completamente diverso in C #. Basti dire che è quando due classi devono trovarsi nello stesso spazio dei nomi per accedere a quei metodi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top