2013-07-08 2 views
0

Я немного подумал о «лучшей практике» в отношении тестируемости и наилучшего способа определить конкретное действие.C# MVC Entity Framework с проверяемостью

В приложении SportsStore (от Pro ASP.NET MVC 4), для AdminController, мы имеем следующие два метода в файле AdminController.cs:

IProductRepository

namespace SportsStore.Domain.Abstract { 
    public interface IProductRepository { 

     IQueryable<Product> Products { get; } 

     void SaveProduct(Product product); //Defined in EFProductRepository 

     void DeleteProduct(Product product); //Defined in EFProductRepository 
    } 
} 

AdminController:

private IProductRepository repository; 

public ViewResult Edit(int productId) { 
    Product product = repository.Products.FirstOrDefault(p => p.ProductID == productId); 
     ... 
    } 

[HttpPost] 
public ActionResult Delete(int productId) { 
     Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId); 
     ... 
    } 

Как я заметил, что мы ба используя тот же бит логики, что и есть идентификатор productID. Если productId вообще изменится, что-то еще, нам нужно изменить это в двух точках. Это может быть легко протестировано, поскольку сам контроллер выполняет вызов Linq.

Я думал, что могу поместить это в эквивалент EFProducts (так что реализация базы данных интерфейса IProducts), но это создает привязку к состоянию базы данных. Я бы хотел избежать этого в своих модульных тестах, поскольку это увеличивает сложность тестирования в достаточной степени.

Есть ли лучшее место для размещения этой логики FindOrDefault, а не в контроллере, но при этом иметь хорошую проверку?

Edit1: Добавление определения для репозитория, который указывает на интерфейс

+0

Поскольку кажется, что вы используете репозиторий, у вас должен быть метод в вашем репозитории с именем 'FindById (int Id)', а затем вы используете этот метод из контроллера вместо того, чтобы каждый раз запускать 'FirstOrDefault'. – SOfanatic

+0

Я не думаю, что репозиторий - это очень интересный тест. Это либо работает, либо нет, и, самое большее, вы можете покрыть это в 1 единичном тесте. Мое предложение состояло в том, чтобы переместить этот код в бизнес-уровень и провести там тестирование. Если вы используете IRepository и DI, вы можете просто высмеять репозиторий. – Maess

+0

Спасибо за отзыв. @SOfanatic. Единственная проблема с добавлением этого в репозиторий - это мои связи с базой данных при тестировании. Добавлено больше кода выше, чтобы надеяться сделать его более понятным, что делает книга. Наличие модульных тестов, привязанных к состоянию базы данных, добавляет много осложнений. – TheDarkTrumpet

ответ

0

ответы под мой вопрос обсудить возможности. И книга, и @maess согласны с тем, что логика для этой конкретной части контроллера. Комментарии по моему вопросу заслуживают внимания, так как и @SOfanatic и @Maess предоставили фантастический вклад.

+0

Когда я читаю комментарии, я интерпретирую разные советы. Maess предлагает вывести логику из контроллера и в сервисный уровень, в то время как SOfanatic предлагает вывести логику из контроллера и поместить ее в репозиторий.В любом случае вы не должны оставлять логику в контроллере. Точно так же, как в Rails, логика должна быть в модели (сервисный уровень/репозиторий), а не в контроллере. –