具有 WCF 调用的单元测试服务 (MSUnit + Moq)

发布于 2024-08-15 07:15:12 字数 2647 浏览 1 评论 0原文

我是 Mocking 的新手,对单元测试有些熟悉,最后决定硬着头皮开始一个采用严格 TDD 方法的新项目。然而,我有一个服务类和方法,我需要回顾性地添加测试,因为它是从原型升级的。

我不知道从哪里开始,但在这个特定的测试中,这是所涉及的类和方法:

public class PageService : IPageService
{
    private readonly ITestService testServiceClient;

    public PageService(ITestService testServiceClient)
    {
        this.testServiceClient = testServiceClient;
    }

    public Page GetPage(Guid websiteId, string pageKey)
    {
        Page builtPage = null;

        // WCF SERVICE CALL I DO NOT WANT EXECUTING WHEN RUNNING UNIT TEST
        // BUT RATHER WANT A BLANK NEW INSTANCE OF "PAGE" CREATED USING MOQ??
        var page = testServiceClient.GetPage(websiteId, pageKey);

        if (page == null)
            return null;

        builtPage = new Page();

        [code here to build builtPage if input params ok] ...

        return builtPage;
    }
}

我正在努力做的是编写一个测试,希望从此我可以扩展 GetPage(.. .) 测试,但对于第一个测试,只需测试是否传入了有效的 websiteIdpageKey,如果是,则接收有效的 Page< /code> 实例返回并在单元测试中断言 true。

testServiceClient 是一个 WCF 服务客户端,它之前被包装在 using() 语句中,但我已将其移出该语句,希望能够通过依赖注入来实现它,如下所示我觉得这将是测试所需的第一步,据我了解,我需要给它一个假/嘲笑? wcf 客户端而不是 testServiceClient.GetPage() 返回已知的内存数据集?希望我走在正确的轨道上。

所以这是我的单元测试的初始蓝图(我使用 Moq 框架,如果您还没有使用最新版本,Setup()Expect() 的新版本起订量):

/// <summary>
/// Tests service returns a valid instance of type `Page` when a valid website and valid page key is tested.
/// </summary>
[TestMethod]
public void Test_Valid_Website_And_Valid_PageKey_Returns_Valid_Instance_Of_Page()
{
    // Arrange
    Page page = null;

    // Act
    var newPage = new Page() { Title = "Mocked Version!?"};

    testServiceClient = new Mock<ITestService>();
    testServiceClient.Setup(x => x.GetPage(websiteId, "about-us")).Returns(newPage);

    service = new PageService(testServiceClient.Object);
    page = service.GetPage(websiteId, "about-us");

    // Assert
    Assert.IsInstanceOfType(page, typeof(Page), "Object was not of expected instance type.");
}

我不知道从这里该去哪里,或者我是否走在正确的道路上?我可以确认上面没有语法错误,并且我确实收到了一个异常:

System.ArgumentException: Invalid setup on a non-overridable member:
x => x.GetPage(websiteId, "about-us").

我所知道的是我希望我的 service.GetPage(...) 返回一个新实例,如 websiteIdpageKey 是有效的,但是我不希望它使用真正的 testServiceClient.GetPage() WCF 调用...希望我理解这个想法正确地嘲笑。当您在该服务上使用 testServiceClient.GetPage 时,我是否通过 Moq 正确告知了它,实际上只是返回一个新的页面实例?

非常感谢任何澄清!谢谢你们!

I am new to Mocking and somewhat familiar with unit testing and finally have decided to bite the bullet on a new project starting up front with a strict TDD approach. However I have one service class and method I need to retrospectively add tests to as it has been promoted from a prototype.

I do not know where to start though on this particular test, this is the classes and methods involved:

public class PageService : IPageService
{
    private readonly ITestService testServiceClient;

    public PageService(ITestService testServiceClient)
    {
        this.testServiceClient = testServiceClient;
    }

    public Page GetPage(Guid websiteId, string pageKey)
    {
        Page builtPage = null;

        // WCF SERVICE CALL I DO NOT WANT EXECUTING WHEN RUNNING UNIT TEST
        // BUT RATHER WANT A BLANK NEW INSTANCE OF "PAGE" CREATED USING MOQ??
        var page = testServiceClient.GetPage(websiteId, pageKey);

        if (page == null)
            return null;

        builtPage = new Page();

        [code here to build builtPage if input params ok] ...

        return builtPage;
    }
}

What I am endeavouring to do, is write one test, from this hopefully I can expand out all permutations of GetPage(...) tests, but for the first one simply test if a valid websiteId and pageKey has been passed in, if so receive a valid Page instance back and assert true to the unit test.

testServiceClient is a WCF service client, this was wrapped in a using() statement before, but I have moved it out of that in hope to get it going with dependency injection as I feel that will be the first step required for testing, as from what I understand, I will need to give it a fake / mocked? wcf client instead where testServiceClient.GetPage() returns a known in-memory set of data? Hopefully I am on the right track there.

So here is my initial blueprints of my unit test (I am using Moq framework, Setup() is the new version of Expect() if you haven't used latest ver of Moq):

/// <summary>
/// Tests service returns a valid instance of type `Page` when a valid website and valid page key is tested.
/// </summary>
[TestMethod]
public void Test_Valid_Website_And_Valid_PageKey_Returns_Valid_Instance_Of_Page()
{
    // Arrange
    Page page = null;

    // Act
    var newPage = new Page() { Title = "Mocked Version!?"};

    testServiceClient = new Mock<ITestService>();
    testServiceClient.Setup(x => x.GetPage(websiteId, "about-us")).Returns(newPage);

    service = new PageService(testServiceClient.Object);
    page = service.GetPage(websiteId, "about-us");

    // Assert
    Assert.IsInstanceOfType(page, typeof(Page), "Object was not of expected instance type.");
}

I have no idea where to go from here, or if I am on the right track? I can confirm the above has no syntax errors, and I do receive an exception:

System.ArgumentException: Invalid setup on a non-overridable member:
x => x.GetPage(websiteId, "about-us").

All I know is that I want my service.GetPage(...) to return a new instance, as websiteId and pageKey was valid, however I don't want it to use the real testServiceClient.GetPage() WCF call... hopefully I understand the idea of mocking correctly. Have I told it correctly through Moq when you use testServiceClient.GetPage on that service, actually just return a new instance of page?

Any clarification is greatly appreciated! Thanks guys!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

分开我的手 2024-08-22 07:15:12

我想说你走在正确的道路上。如果 ITestService 确实是一个接口(如其名称所示),您将能够模拟它。

但是,当您定义设置时,Moq 必须能够识别您所指的方法,并且似乎您以某种方式指示了接口上不存在的方法。

您没有向我们展示 ITestService 接口,我们也不知道 websiteId 变量的类型。

如果您仔细查看 Setup 方法,您会发现它实际上是一个泛型方法,因此当您在没有泛型参数的情况下调用它时,会进行类型推断。

我的猜测是 websiteId 的声明在某种程度上与 GetPage 的声明发生冲突。例如,如果 websiteId 被声明为 object,Moq 将处理具有此签名的方法:

Page GetPage(object x, string y);

这与在任何情况下都不一样

Page GetPage(Guid x, string y);

,一旦您设法让安装程序正常工作,您关于单元测试的基本想法似乎不错。您可以做的不仅仅是断言实例不为空,因为模拟将确保返回的实例与您最初设置的实例相同:

[TestMethod]
public void Test_Valid_Website_And_Valid_PageKey_Returns_Valid_Instance_Of_Page()
{
    // Arrange
    Page page = null;

    // Act
    var newPage = new Page() { Title = "Mocked Version!?"};

    testServiceClient = new Mock<ITestService>();
    testServiceClient.Setup(x => x.GetPage(websiteId, "about-us")).Returns(newPage);

    service = new PageService(testServiceClient.Object);
    page = service.GetPage(websiteId, "about-us");

    // Assert
    Assert.AreEqual(newPage, page);
}

请注意更有价值的断言。

I would say that you are on the right track. If ITestService truly is an interface (as indicated by its name), you will be able to Mock it.

However, when you define your Setups, Moq must be able to identify which method you meant, and it seems as though you somehow indicate a method that doesn't exist on the interface.

You didn't show us the ITestService interface, and neither do we know the type of the websiteId variable.

If you take a closer look at the Setup method you will see that it's really a generic method, so there's type inferencing going on when you call it without the generic parameters.

My guess is that the declaration of websiteId somehow clashes with the declaration of GetPage. If, for example, websiteId was declared as object, Moq would look after a method with this signature:

Page GetPage(object x, string y);

which isn't the same as

Page GetPage(Guid x, string y);

In any case, once you manage to get the Setup to work, your basic idea about the unit test seems fine. You can do more than just asserting that the instance isn't null, because the Mock will ensure that the instance returned is the same as the instance you originall set up:

[TestMethod]
public void Test_Valid_Website_And_Valid_PageKey_Returns_Valid_Instance_Of_Page()
{
    // Arrange
    Page page = null;

    // Act
    var newPage = new Page() { Title = "Mocked Version!?"};

    testServiceClient = new Mock<ITestService>();
    testServiceClient.Setup(x => x.GetPage(websiteId, "about-us")).Returns(newPage);

    service = new PageService(testServiceClient.Object);
    page = service.GetPage(websiteId, "about-us");

    // Assert
    Assert.AreEqual(newPage, page);
}

Notice the much more valuable Assert.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文