4

我正在使用 Moq 创建 HttpResponseBase 的模拟对象。我需要能够测试在我的库中调用了 HttpResponseBase.End() 。为此,我在调用之前指定了一些文本,在调用之后指定了一些文本。然后我检查 HttpResponseBase.Output 中只有调用 End() 之前的文本。

问题是,我不知道如何模拟 HttpResponseBase.End() 以便它停止处理,就像在 ASP.NET 中那样。

public static HttpResponseBase CreateHttpResponseBase() {
    var mock = new Mock<HttpResponseBase>();
    StringWriter output = new StringWriter();

    mock.SetupProperty(x => x.StatusCode);
    mock.SetupGet(x => x.Output).Returns(output);
    mock.Setup(x => x.End()) /* what do I put here? */;
    mock.Setup(x => x.Write(It.IsAny<string>()))
        .Callback<string>(s => output.Write(s));

    return mock.Object;
}
4

1 回答 1

2

我有点不清楚你想要实现什么,但从你的描述来看,听起来你正试图让你的 Abstraction 表现得像一个特定的实现。换句话说,因为 HttpResponse.End() 有一定的行为,你希望你的 Mock 有同样的行为吗?

一般来说,使用 Moq 并不是特别容易做到这一点,因为它没有有序期望的概念(与 RhinoMocks 不同)。但是,它有一个功能请求

您也许可以使用 Callback 和设置 End 方法来切换一个标志,该标志确定 Mock 的任何进一步行为,但它不会特别漂亮。我正在考虑这样的事情:

bool ended = false;
var mock = new Mock<HttpResponseBase>();
mock.Setup(x => x.End()).Callback(() => ended = true);
// Other setups involving 'ended' and Callbacks

然后让所有其他设置具有基于ended是真还是假的双重实现。

这会非常丑陋,所以我现在会认真地重新考虑我的选择。您至少可以采取两个方向:

  1. 制作 HttpResponseBase 的假实现,而不是使用 Moq。听起来您期待实现的这种特定行为,以至于带有嵌入式逻辑的 Test Double 听起来是一个更好的选择。简而言之,Fake 是一个测试替身,可以包含模仿预期生产实现的半复杂逻辑。您可以在优秀的xUnit 测试模式一书中阅读更多关于 Fakes 和其他测试替身的信息。
  2. 重新考虑你最初的假设。在我看来,您将客户端与 HttpResponseBase 的特定行为非常紧密地联系在一起,因此您可能违反了 Liskov 替换原则。但是,我可能弄错了,因为一种称为“End”的方法具有超出纯粹语义的某些含义,但我个人还是会考虑是否有可能进行更好的设计。
于 2009-07-26T11:27:35.400 回答