In Unit Testing, perché dovrei creare un repository due volte?


10

L'altro giorno stavo leggendo un po 'di Unit Testing e ho visto alcuni esempi in cui le persone creano un'interfaccia repository (cioè IExampleRepository) e quindi creano il repository reale ( public class ExampleRepository : IExampleRepository) e un repository da utilizzare per unit test ( FakeExampleRepository : IExampleRepository).

Nel IExampleRepositorystavano implementando gli stessi metodi come nel ExampleRepository, tuttavia con query Linq diverse.

Qual è esattamente l'obiettivo qui? Ho pensato che una parte del test del tuo codice è assicurarsi che un metodo funzioni correttamente? Ma quando uso due query totalmente diverse, una per "reale" e una nel test, che senso ha il test?

Risposte:


8

Uno degli obiettivi del test unitario è testare solo una cosa alla volta, ovvero una singola classe e metodo. Se il repository stesso non è sotto test, normalmente lo deriderebbe in qualche modo in modo da testare la logica nel metodo / classe.

Detto questo, è necessario testare anche con un repository "reale" *, ma normalmente ciò avverrebbe in un test di integrazione / sistema

* ovviamente reale come nel repository impostato per il test, si spera non per esempio nel DB di produzione.


Quindi nel test unitario non testerò il metodo stesso per assicurarmi che restituisca i valori corretti (basato su un set di dati falso / deriso)?
jao,

sì, testerai il metodo stesso ma solo il codice nel metodo, il codice in altri oggetti dovrebbe essere coperto in altri test unitari, l'interazione di più oggetti dovrebbe essere coperta nei test di integrazione o nei test di livello superiore
jk.

1
Ok, quindi se ho capito bene, dovrei usare il repository originale quando l'unità verifica i repository. Non ho bisogno di testarli quando scrivo unit test per i controller (nel caso di Asp.Net MVC)
jao

4
@Theomax Dipende dal contesto: se stai testando un'unità di un componente software che non è tuo ExampleRepository, allora è meglio usare una simulazione. La giustificazione è che non stai testando l'unità del repository ma qualcos'altro.
Andres F.

5
@Theomax Per espandere il commento di AndresF.: Se stai testando le unità ExampleRepository, usa la cosa reale. Se si esegue il test unitario RepositoryController, è consigliabile utilizzare solo un valore FakeExampleRepositoryche restituisce valori predefiniti. In questo modo, se un bug si insinua in ExampleRepository, solo quel test unitario fallirà - RepositoryControlleri test continueranno ad avere successo, quindi sai che non c'è un bug lì. Se il controller utilizzasse il vero repository, entrambi
fallirebbero

5

Sono d'accordo con le due risposte di jk. e Jan Hudec - forniscono alcune informazioni davvero utili. Ma ho pensato di aggiungere un po '.

La tua prima domanda ("Qual è esattamente l'obiettivo qui?") È importante. Nel caso in cui stai descrivendo, il vero obiettivo è testare le classi che utilizzano l' IExampleRepositoryinterfaccia, non testare le implementazioni del repository. La creazione di FakeExampleRepositoryconsente di testare quelle classi client senza preoccuparsi dei dettagli della classe di repository reale.

Ciò è particolarmente vero se l'oggetto che si sta tentando di configurare rende difficili i test (ad es. Accede al file system, chiama un servizio web o parla con un database). Usando le interfacce (e altre tecniche simili), si mantiene basso l'accoppiamento. Pertanto, la classe Xdeve solo conoscere l'interfaccia e non è necessario conoscere i dettagli dell'implementazione. L'obiettivo è assicurarsi che la classe Xstia facendo la cosa giusta.

Il deridere (o il mozzare, falsificare ... ci sono differenze sfumate) è un potente strumento per test unitari e TDD. Ma può essere una seccatura creare e mantenere manualmente queste implementazioni. Pertanto, la maggior parte delle lingue ora ha librerie beffardo per aiutare. Dato che stai usando C #, consiglierei Moq perché è semplice e molto potente. Quindi è possibile testare l'interfaccia senza accumulare codice aggiuntivo per le implementazioni simulate.


the real objective is to test the classes that are utilizing the IExampleRepository interfacequesto non è strettamente vero. L'obiettivo è testarlo indipendentemente da IExampleRepository. +1 per aver raccomandato un buon quadro di isolamento.
StuperUser

1
Non sono d'accordo. Non è indipendente dal IExampleRepositoryperché la classe sotto test è accoppiata a quell'interfaccia. Ma è indipendente da qualsiasi implementazione dell'interfaccia. Devo ammettere che probabilmente la mia spiegazione potrebbe usare un po 'più di finezza. :)
Allan,

5

Qual è esattamente l'obiettivo qui?

Isolamento.

L'idea di un'unità lo testa per testare l' unità di codice più piccola possibile . Puoi farlo isolandolo da tutti gli altri codici di produzione nel test.

Creando classi false, l'unico codice di produzione è la classe sottoposta a test.

Se si crea correttamente un repository falso e il test ha esito negativo, si sa che il problema riguarda il codice in fase di test. Questo ti dà il vantaggio della diagnosi gratuitamente.

Dai un'occhiata ai framework di isolamento (come Moq come suggerito da @Allan) per essere in grado di generare rapidamente questi falsi per impostare condizioni di test e usarli per affermare.


Maggiori dettagli su falsi, deride e mozziconi: stackoverflow.com/questions/346372/...
StuperUser

4

Esistono tre motivi per cui potresti voler fornire un'istanza finta al test unitario:

  1. Vuoi limitare l'ambito del test, in modo che il test non sia influenzato dai bug nel depndee, probabilmente perché non è ancora finito o non è stabile o non vuoi che i bug negli altri influenzino i tuoi test.
  2. Il dipendente è complicato da configurare. Ad esempio, il livello di accesso ai dati viene spesso deriso, poiché quello reale richiede la creazione di un database di prova. È ancora necessario testare il livello di accesso ai dati reali, ma è possibile limitare l'installazione costosa durante il debug di altre cose.
  3. Per verificare che la classe dipendente reagisca correttamente a vari tipi di errori, fornisci una versione finta che restituisce ogni tipo di risposta errata. Perché molte modalità di errore sono piuttosto difficili da riprodurre, ma dovrebbero comunque essere testate.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.