2013-05-14 14 views
5

Próbuję wykonać test na kontrolerach, które pobierają dane z klas repozytorium. Jest to część repozytorium chcę testu:Jak powinieneś testować jednostki z klasami repozytoriów w MVC3?

public class NewsRepository 
{ 
    public IEnumerable<NewsItem> GetNews() 
    { 
     var result = (from n in n_db.NewsItems 
        orderby n.ID descending 
        select n).Take(3); 
     return result; 
    } 
} 

Tylko niektóre małe kod, aby uzyskać jak testowanie działa. W moim HomeController Mam ten kod wewnątrz Index():

public ActionResult Index() 
    { 
     ViewBag.Message = "Announcements"; 
     NewsRepository n_rep = new NewsRepository(); 
     var model = i_rep.GetNews(); 

     return View(model); 
    } 

Jestem zupełnie nowe do testowania więc wszystkie wyjaśnienia byłoby świetnie. Dzięki.

Odpowiedz

8

Twój kontroler jest niemożliwe, aby być testowane w izolacji jednostki, ponieważ jest silnie sprzężony z repozytorium na następującej linii:

NewsRepository n_rep = new NewsRepository(); 

Ty po prostu sztywno konkretną implementację repozytorium iw swoim testów jednostkowych ty nie można tego wyśmiać. W tym celu należy prawidłowo należy rozpocząć od zdefiniowania abstrakcję nad repozytorium:

public interface INewsRepository 
{ 
    IEnumerable<NewsItem> GetNews(); 
} 

a następnie mieć swoje specyficzne repozytorium wdrożyć ten interfejs:

public class NewsRepository : INewsRepository 
{ 
    ... 
} 

Ok teraz, że mamy abstrakcję niech osłabiać sprzężenie między dostępem do danych i logiką sterownika za pomocą tej abstrakcji:

public class NewsController: Controller 
{ 
    private readonly INewsRepository repository; 
    public NewsController(INewsRepository repository) 
    { 
     this.repository = repository; 
    } 

    public ActionResult Index() 
    { 
     ViewBag.Message = "Announcements"; 
     var model = this.repository.GetNews(); 
     return View(model); 
    }  
} 

Dobra, teraz masz kontroler, który nie jest już mocno w połączeniu z pewną konkretną realizacją. Możesz pobrać swoją ulubioną symulację i napisać test jednostkowy. Na przykład z NSubstitute oto jak testy jednostkowe w działaniu Index może wyglądać następująco:

[TestMethod] 
public void Index_Action_Fetches_Model_From_Repo() 
{ 
    // arrange 
    var repo = Substitute.For<INewsRepository>(); 
    IEnumerable<NewsItem> expectedNews = new[] { new NewsItem() }; 
    repo.GetNews().Returns(expectedNews); 
    var sut = new NewsController(repo); 

    // act 
    var actual = sut.Index(); 

    // assert 
    Assert.IsInstanceOfType(actual, typeof(ViewResult)); 
    var viewResult = actual as ViewResult; 
    Assert.AreEqual(expectedNews, viewResult.Model); 
} 

I to dość dużo. Twój kontroler jest teraz łatwo testowany w pojedynkę. Nie musisz konfigurować baz danych ani cokolwiek innego. To nie jest kwestia testowania logiki sterownika.

+0

To ma wiele sensu i nie widzę powodu, dla którego nie jest to rozwiązanie, którego szukam, ale dostaję te błędy: 1. w publicznym NewsController (repozytorium INewsRepository) Błąd jest: niespójny dostępność: typ parametru "TestProject.Models.INewsRepository" jest mniej dostępny niż metoda "TestProject.Controllers.NewsController.NewsController (TestProject.Models.inewsRepository)" ---- 2. w wierszu: var repo = Substitute.For < INewsRepository>(); Błąd: nazwa "Substitute" nie istnieje w bieżącym kontekście. ---- Czy jest jakaś przestrzeń nazw, której może mi brakować? – Mappan

+0

Zastępstwo, zapomniałem sprawdzić link. Ale pierwszy błąd stoi. – Mappan

+0

Wszystkie twoje klasy i interfejsy muszą być "publiczne", jak pokazano w mojej odpowiedzi. Jeśli chodzi o twój błąd dotyczący NSubstitute, musisz zainstalować NSubstitute NuGet w swoim projekcie testowym jednostki. –

Powiązane problemy