bak*_*san 26 c# abstraction mocking
我一直在完成清理控制器代码的过程,以使每个操作都可测试.一般来说,这并不是太困难 - 我们有机会使用固定对象,比如说FormsAuthentication,我们通常会在适当的时候引入某种形式的包装器并且是我们喜欢的方式.
由于没有特别与此对话密切相关的原因,在处理HttpContext的使用时,我们决定使用新创建的HttpContextWrapper类而不是发明自己开发的东西.我们介绍的一件事是能够交换HttpContextWrapper(比如说,用于单元测试).这完全受到Oren Eini使用DateTimes处理单元测试的方式的启发(参见文章,我们也使用的模式)
public static class FooHttpContext
{
public static Func<HttpContextWrapper> Current = ()
=> new HttpContextWrapper(HttpContext.Current);
public static void Reset()
{
Current = () => new HttpContextWrapper(HttpContext.Current);
}
}
Run Code Online (Sandbox Code Playgroud)
没什么特别的花哨.它在我们的控制器代码中运行得很好.当我们去编写单元测试时,就会出现这个问题.我们使用Moq作为我们的模拟框架,但是唉
var context = new Mock<HttpContextWrapper>()
Run Code Online (Sandbox Code Playgroud)
因为HttpContextWrapper没有无参数的ctor,所以会中断.作为ctor参数需要什么?一个HttpContext对象.所以我发现自己陷入困境22.
我正在使用规定的方法来解耦HttpContext - 但我无法模拟一个值,因为原始的HttpContext对象是密封的,因此很难测试.我可以映射HttpContextBase,它们都来自 - 但这并没有真正让我得到我想要的东西.我是否只是忽略了HttpContextWrapper的某个方面?
编辑以澄清意图
我们找到了解决问题的方法 - 但我想我们最终要解决的问题是HttpContextWrapper给表带来了什么价值?我不怀疑某个人完全有一个哈哈!它的时刻,但它不会来找我.我在这里看到的大多数帖子都在可测试性方面进行了讨论 - 但是我自己的经验让我相信它并没有带来太大的影响.除非我们做错了.(完全可能).
Dar*_*rov 34
您应该使用HttpContextBase更容易模拟的抽象而不是HttpContextWrapper.
public static Func<HttpContextBase> Current =
() => new HttpContextWrapper(HttpContext.Current);
Run Code Online (Sandbox Code Playgroud)
在你的单元测试中:
SomeClass.Current = MockHttpContextBase(); // Sorry I don't know the syntax for Moq
Run Code Online (Sandbox Code Playgroud)
cod*_*ike 34
这篇博文很好地解释了它:
http://splinter.com.au/httpcontext-vs-httpcontextbase-vs-httpcontext
关键是'vintage'HttpContext没有实现HttpContextBase,并且不是虚拟的,因此不能被Mocked.HttpContextBase在3.5中被引入作为可模拟的替代方案.但是仍然存在老式HttpContext 没有实现 HttpContextBase的问题.
因此,HttpContextWrapper是一个方便的包装类(或"kludge"),它实现了HttpContextBase,并且可以在使用IOC注入"真正的"HttpContext时使用,通常使用如下工厂方法: () => new HttpContextWrapper(HttpContext.Current)