本文介绍了如何嘲笑/存根或简单地忽略了Htt prequest时,单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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有具体的依赖性在这里,所以我不能进行单元测试我的控制器。我不想嘲笑HTTP请求,因为我只是想测试控制器,而不是DeviceDetection模块。

Problem:The DeviceDetection has concrete dependency here so I can't unit test my controller. I don't want to Mock the Http request since I just want to test the controller and not DeviceDetection module.

我如何可以模拟/避免访问这个(Request.ServerVariables [HTTP_X_REWRITE_URL]。的ToString())

How can i mock/avoid accessing this (Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString())

这是造成所有的问题。

推荐答案

要回答你的问题,你需要在你的测试以下内容:

To answer your question, you need the following in your test:

        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;  

然而,由于@马克建议你不需要到你的动作中创建 DeviceDetection 的具体的实例,你需要注入它。但是,而不是注入具体的实例,最好是把它包装成接口 IDeviceDetector 并注入这种抽象。

However as @Mark suggested you don't need to create concrete instance of DeviceDetection inside your action, you need to inject it. But instead of injecting a concrete instance, it is better to wrap it into interface IDeviceDetector and inject this abstraction.

我给具有许多优点:


  1. 您的行为不依赖于执行 DeviceDetection

  2. 模拟&LT; IDeviceDetection&GT; 允许您引发异常的设置,测试的异常处理你的的try-catch 块。

  3. 您可以断言, DetectDevice()方法被称为

  1. Your action does not depend on the implementation of DeviceDetection
  2. Mock<IDeviceDetection> allows you to raise exception on setup, to test exception handling of your try-catch block.
  3. You can assert that DetectDevice() method is called

另一个建议 - 从来不使​​用尝试{}赶上(例外前){} ,你应该只捕获那些可以处理异常。因为你不知道哪些异常类型可以被抛出,以及如何有效地处理它,例如它可以是 OutOfMemoryException异常。 可以给你不同的方式来处理基本思路例外MVC。

Another suggestion - never use try{} catch(Exception ex){}, you should catch only those exceptions which you can handle. As you don't know which type of exception can be thrown and how to handle it effectively, e.g. it can be OutOfMemoryException. This article can give you basic ideas of different ways to handle exception in MVC.

更新:当我看到你在使用Unity作为IoC容器。团结具有可能性注入构造函数的参数。如此反复,你需要提取 DeviceDetector 的接口让我们说 IDeviceDetector 。注册它

UPDATE: As I see you are using Unity as IoC container. Unity has a possibility to inject constructor parameters. So again you need to extract an interface from DeviceDetector let's say IDeviceDetector. Register it

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

注册 DeviceDetector TransientLifetimeManager

然后你的控制器看起来应该像

Then your controller should look like

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);
    }
}

请注意,在这种情况下,你需要编写单元测试您的统一的容器,以验证您注射正确解析。单元测试可能看起来像:

Note, in this case you need to write unit tests for your Unity container to verify that your injections are resolved correctly. Your unit test may look like:

[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());
}

这篇关于如何嘲笑/存根或简单地忽略了Htt prequest时,单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-13 20:45