2015-11-27 2 views
2
public class DemoController : Controller 
{ 
    private readonly ICommonOperationsRepository _commonRepo; 
    public DemoController (ICommonOperationsRepository commonRepo) 
    { 
     _commonRepo = commonRepo; 
    } 

    public ActionResult Default() 
    { 
     var model = new DemoModel(); 
     try 
     { 
      **DeviceDetection dd = new DeviceDetection(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString()); 
      dd.DetectDevice();** 

      model.ListTopListing.AddRange(_commonRepo.GetListings()); 
     } 
     catch (Exception ex) 
     { 
      ExceptionHandler objErr = new ExceptionHandler(ex, "DemoController .Default()\n Exception : " + ex.Message); 
      objErr.LogException(); 
     } 
     return View(model); 
    } 
} 

Проблема: DeviceDetection имеет конкретную зависимость здесь, поэтому я не могу выполнить тестирование моего контроллера. Я не хочу Mock запрос Http, так как я просто хочу протестировать контроллер, а не модуль DeviceDetection.Как сфокусировать/заглушить или просто игнорировать HttpRequest при модульном тестировании

Как я могу издеваться/избегают получать доступ к этому (Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString())

, которая является причиной всех проблем.

ответ

1

Чтобы ответить на ваш вопрос, вам необходимо следующее в тесте:

 var requestBase = new Mock<HttpRequestBase>(); 
     requestBase.Setup(r => r.ServerVariables) 
       .Returns(new NameValueCollection { {"HTTP_X_REWRITE_URL", "your url"} }); 

     var httpContext = new Mock<HttpContextBase>(); 
     httpContext.Setup(x => x.Request).Returns(requestBase.Object); 

     var ctrCtx = new Mock<ControllerContext>(); 
     ctrCtx.Setup(x => x.HttpContext).Returns(httpContext.Object); 

     demoController.ControllerContext = ctrCtx.Object; 

Однако, как @Mark предложил вам не нужно создавать конкретный экземпляр DeviceDetection внутри ваших действий, вы должны вводить его. Но вместо того, чтобы вводить конкретный экземпляр, лучше обернуть его в интерфейс IDeviceDetector и ввести эту абстракцию.

даст ряд преимуществ:

  1. Вашего действие не зависит от реализации DeviceDetection
  2. Mock<IDeviceDetection> позволяет поднять исключение на установке, чтобы проверить обработку исключений вашего try-catch блока.
  3. Можно утверждать, что DetectDevice() метод называется

Еще одно предложение - никогда не использовать try{} catch(Exception ex){}, вы должны поймать только те исключения, которые вы можете справиться. Поскольку вы не знаете, какой тип исключения может быть брошен и как эффективно его обрабатывать, например, это может быть OutOfMemoryException. This article может дать вам основные идеи о различных способах обработки исключений в MVC.

UPDATE: Как я вижу, вы используете Unity в качестве контейнера IoC. Unity имеет возможность inject constructor parameters. Так что вам нужно извлечь интерфейс с DeviceDetector, скажем, IDeviceDetector. Зарегистрируйте

container.RegisterType<IDeviceDetector, DeviceDetector>(new InjectionConstructor(
HttpContext.Current.Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString())); 

регистр DeviceDetector с TransientLifetimeManager.

Затем контроллер должен выглядеть

public class DemoController : Controller 
{ 
    private readonly ICommonOperationsRepository _commonRepo; 
    private readonly IDeviceDetection _deviceDetection; 

    public DemoController (
     ICommonOperationsRepository commonRepo, 
     IDeviceDetection deviceDetection) 
    { 
     _commonRepo = commonRepo; 
     _deviceDetection = deviceDetection; 
    } 

    public ActionResult Default() 
    { 
     var model = new DemoModel(); 

     _deviceDetection.DetectDevice(); 
     model.ListTopListing.AddRange(_commonRepo.GetListings()); 

     return View(model); 
    } 
} 

Примечания, в этом случае вам нужно писать тесты для вашего контейнера Unity, чтобы убедиться, что ваши инъекции решены правильно. Ваш блок-тест может выглядеть так:

[TestMethod] 
public void Test() 
{ 
    var repository = new Mock<ICommonOperationsRepository>(); 
    var deviceDetection = new Mock<IDeviceDetection>(); 

    var controller = new DemoController(repository.Object, deviceDetection.Object); 
    controller.Default(); 

    deviceDetection.Verify(x => x.DetectDevice(), Times.Once()); 
} 
+0

Это дает мне полное исключение ссылки, как только я создаю DetectDevice. – maverick

+0

Можете ли вы опубликовать код вашего теста? –

+0

var usedController = new UsedController (новый CommonOperationsRepository()); var requestBase = new Mock (); requestBase.Setup (r => r.ServerVariables) . Возвраты (новое имяValueCollection {{"HTTP_X_REWRITE_URL", "/ used /"}}); var httpContext = new Mock (); httpContext.Setup (x => x.Request). Возвраты (requestBase.Object); – maverick

1

Сделать DeviceDetectionconcrete dependency из DemoController:

public class DemoController : Controller 
{ 
    private readonly ICommonOperationsRepository _commonRepo; 
    private readonly DeviceDetection dd; 

    public DemoController (
     ICommonOperationsRepository commonRepo, 
     DeviceDetection dd) 
    { 
     _commonRepo = commonRepo; 
     this.dd = dd; 
    } 

    public ActionResult Default() 
    { 
     var model = new DemoModel(); 
     try 
     { 
      this.dd.DetectDevice(); 
      model.ListTopListing.AddRange(_commonRepo.GetListings()); 
     } 
     catch (Exception ex) 
     { 
      ExceptionHandler objErr = new ExceptionHandler(ex, "DemoController .Default()\n Exception : " + ex.Message); 
      objErr.LogException(); 
     } 
     return View(model); 
    } 
} 

Это позволит вам создать экземпляр DemoController, не полагаясь на Request собственности:

var sut = new DemoController(someStupRepository, new DeviceDetection("foo")); 

Вы можете сделать это в, например, единичный тест.

Когда вы вносите DemoController в свою заявку, вы переходите в request.ServerVariables["HTTP_X_REWRITE_URL"].ToString() в DeviceDetection. Вы можете получить переменную request из аргумента requestContextCreateController.

+0

Я не знаю, как контроллер контроллера называется так называемым экземпляром. Я получаю, как это сделать для модульного теста, но как это сделать для определения исходного контроллера? – maverick

+0

У вас уже есть зависимость от 'ICommonOperationsRepository' в' DemoController'. Как вы это сочиняете? –

+0

Я разместил файл Unity Bootstraper: container.RegisterType () – maverick

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