2016-04-04 5 views
0

Я могу заставить его работать, но я хочу знать, что такое лучшая практика и почему. У меня есть контроллер, модель и репозиторий, и теперь я хочу, чтобы модуль тестировал контроллер. Я просто пишу простой тест, чтобы убедиться, что верное представление возвращается.Блок тестирования контроллера - как обрабатывать строку соединения?

Это мой метод в контроллере:

public ActionResult Selections(SelectionsViewModel model) 
    { 
     for (int i = 0; i < model.Sends.Count; i++) 
     { 
      Send send = new Send(new SendService(new Database().GetConnectionString())) 
      { 
       SendID = model.Sends[i].SendID, 
       Title = model.Sends[i].Title, 
       Subject = model.Sends[i].Subject, 
       SentDate = model.Sends[i].SentDate, 
       TimesViewed = model.Sends[i].TimesViewed, 
       Include = model.Sends[i].Include, 
       Exclude = model.Sends[i].Exclude 
      }; 
      send.UpdateIncludeExclude(); 
     } 

     return View(model); 
    } 

Вот мой метод GetConnectionString() в классе базы данных, которые отправляются через мой конструктор SendService.

public string GetConnectionString() 
    { 
     return System.Configuration.ConfigurationManager.ConnectionStrings["DEVConnectionString"].ToString(); 
    } 

И, наконец, мой блок тест:

[Test] 
    public void TestAssignmentSelections() 
    { 
     var obj = new AssignmentController(); 

     var actResult = obj.Selections() as ViewResult; 

     NUnit.Framework.Assert.That(actResult.ViewName, Is.EqualTo("Selections")); 
    } 

Теперь, мой блок тест не пройден, и я понимаю, почему. Мой проект модульного тестирования не имеет доступа к web.config проекта, который я тестирую, где находится моя строка подключения.

Я провел некоторое исследование, и, по-видимому, просто добавив web.config в свой проект модульного тестирования и установив там строку соединения, это сделает его работу .. но это похоже на взлома.

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

ответ

3

Вы хотите, чтобы ваш блок контроллера прошел проверку? Не делай этого.

new SendService(

С помощью этого кода, вы жестко прописывать вашу конкретную реализации услуг & вашей реализации коды доступа к данным. В вашем модульном тесте вы не должны получать доступ к данным из своей базы данных. Вместо этого вы должны обеспечить реализацию ложного доступа к данным.

Здесь идут интерфейсы, вам необходимо создать интерфейс для вашего SendService.

public interface ISendService 
{ 
    void SomeMethod(); 
} 

теперь ваш SendService будет конкретная реализация этого интерфейса

public class SendService : ISendService 
{ 
    public void SomeMethod() 
    { 
    // Do something 
    } 
} 

Теперь обновить контроллер, чтобы иметь конструктор, где мы будем впрыснуть реализацию ISendService.

public class YourController : Controller 
{ 
    private ISendService sendService; 
    public YourController(ISendService sendService) 
    { 
    this.sendService = sendService; 
    }  
    public ActionResult YourActionMethod() 
    { 
    // use this.sendService.SomeMethod(); 
    } 
} 

И вы можете использовать некоторые рамки для инъекций зависимости сказать фреймворку, реализация интерфейса, используемую при выполнении кода. Если вы используете MVC6, у него есть встроенный поставщик инъекций зависимостей, который вы можете использовать. Итак, перейдите к классу Startup и в своем методе ConfigureServices вы можете сопоставить интерфейс с конкретной реализацией.

public class Startup 
{ 
    public void ConfigureServices(IServiceCollection services) 
    { 
    services.AddTransient<ISendService, SendService>(); 
    } 
} 

Если в предыдущей версии MVC, Вы можете рассмотреть рамки DI как Unity, Ninject и т.д. Вы можете сделать такой же подход для доступа к данным более позднего/Сервис слоев. т.е.: создать интерфейс для доступа к данным и ввести его в свой SendService.

public Interface IDataAccess 
{ 
    string GetName(int id); 
} 

и реализация, которая использует свой определенный код доступа к данным/ORM

public class EFDataAccess : IDataAccess 
{ 
    public string GetName(int id) 
    { 
    // return a string from db using EF 
    } 
} 

Так что теперь ваш класс Service будет

public class SendService : ISendService 
{ 
    private IDataAccess dataAccess; 
    public SendService(IDataAccess dataAccess) 
    { 
    this.dataAccess=dataAccess; 
    } 
    // to do : Implement methods of your ISendService interface. 
    // you may use this.dataAccess in those methods as needed. 
} 

В модульных тестов, вы можете создать макет реализация ваших интерфейсов, которая возвращает статические данные вместо доступа к базе данных.

Например, если вы используете фальшивый фреймворк Moq, вы можете это сделать.

var m = new Mock<IDataAccess>(); 
var m.Setup(s=>s.GetName(It.IsAny<int>())).Returns("Test"); 
var s = new SendService(m); 
var result= s.SomeMethod(); 
+0

Это было полезно, я думаю, у меня есть некоторые изменения. Спасибо. – halterdev

Смежные вопросы