【问题标题】:Unit testing / mocking XML-RPC.net calls单元测试/模拟 XML-RPC.net 调用
【发布时间】:2013-01-11 12:26:47
【问题描述】:

我正在开发一个使用 CookComputing XML-RPC.net 的应用程序

我的问题是如何对调用外部 rpc 方法的方法进行单元测试。

如果我们以网站上的例子为例:

//This is the XML rpc Proxy interface
[XmlRpcUrl("http://www.cookcomputing.com/xmlrpcsamples/RPC2.ashx")]
public interface IStateName : IXmlRpcProxy
{
    [XmlRpcMethod("examples.getStateName")]
    string GetStateName(int stateNumber); 
}


public class MyStateNameService 
{
    public string GetStateName(int stateNumber)
{
        IStateName proxy = XmlRpcProxyGen.Create<IStateName>();
        return proxy.GetStateName(stateNumber);
     }
}

我们如何在不实际命中的情况下有效地测试 IStateName 的结果 http://www.cookcomputing.com/xmlrpcsamples/RPC2.ashx

我想一个好的开始是MyStateNameService 上的构造函数采用 IStateName,并在 IStateName 上传入一个假的(或模拟的?)实例...

我有兴趣测试它的实际内容——例如伪造来自端点的响应,并以某种方式返回它,而不仅仅是验证 GetStateName 调用服务...

编辑

我并没有试图测试服务的内容本身,以及 my 类对它的作用。

例如,假设响应是:

<?xml version="1.0"?>
<methodResponse>
  <params>
    <param>
        <value><string>My State Name</string></value>
    </param>
  </params>
</methodResponse>

我想“伪造”该响应,以了解如何测试 MyStateNameService.GetStateName 实际返回的“我的州名”

【问题讨论】:

  • 为什么要测试内容?当然,一旦它到达IStateName 代理,它就不再是您的应用程序所关心的问题了。不要测试外部代码,这取决于编写库的人!
  • 对不起...我将编辑问题以使其更清楚。请查看已编辑的问题
  • 我仍然不确定这一点。如果我错了,请纠正我,但是您不直接处理 XML,而是调用代理上的一个方法,该方法创建一个请求,并将其发送到为 RPC 提供服务的任何事物。响应返回到代理,然后解析输出并将其提供给您?在这种情况下,您无法控制 XML 解析,由库的代理类完成,那么您为什么要测试它呢?
  • 还有更多,如果您无权访问库的内部,我不确定您是否可以测试它...
  • 目前,我连接到实时服务器来测试我的服务。这似乎有点矫枉过正。本质上,服务器所做的只是返回一大块 XML。 XML RPC 库正在解析它。到目前为止一切顺利,但我想测试我的类/结构是否与返回的 xml 等匹配......

标签: c# unit-testing mocking nunit xml-rpc


【解决方案1】:

您的问题在于此处应用的单例模式。

XmlRpcProxyGen.Create<IStateName>();

因此,您使用依赖注入(通过构造函数)的想法是一个好的开始。 (你使用 IoC 容器吗?)

接下来是为IStateName 服务创建一个Mock/Fake/Stub。 这可以通过多种方式实现。

使用动态模拟系统可能会为您节省一些工作,但您需要了解它们的用法。

使用 NUnit、NSubstitute 和修改后的 MyStateNameService 的经典 AAA 测试示例:

class MyStateNameService
{
  private readonly IStateName _remoteService;
  public MyStateNameService(IStateName remoteService)
  {
    // We use ctor injection to denote the mandatory dependency on a IStateName service
    _remoteService = remoteService;
  }

  public string GetStateName(int stateNumber)
  {
    if(stateNumber < 0) throw new ArgumentException("stateNumber");
    // Do not use singletons, prefer injection of dependencies (may be IoC Container)
    //IStateName proxy = XmlRpcProxyGen.Create<IStateName>();
    return _remoteService.GetStateName(stateNumber);
  }
}

[TestFixture] class MyStateNameServiceTests
{
  [Test]
  public void SomeTesting()
  {
    // Arrange
    var mockService = Substitute.For<IStateName>();
    mockService.GetStateName(0).Returns("state1");
    mockService.GetStateName(1).Returns("state2");

    var testSubject = new MyStateNameService(mockService);


    // Act
    var result = testSubject.GetStateName(0);

    // Assert
    Assert.AreEqual("state1", result);

    // Act
    result = testSubject.GetStateName(1);

    // Assert
    Assert.AreEqual("state2", result);

    // Act/Assert
    Assert.Throws<ArgumentException>(() => testSubject.GetStateName(-1));
    mockService.DidNotReceive().GetStateName(-1);

    /* 
       MyStateNameService does not do much things to test, so this is rather trivial.
       Also different use cases of the testSubject should be their own tests ;) 
    */


  }

}

【讨论】:

  • 是的,我知道我需要做什么,只是在这里寻找更深入的答案....我可能会使用起订量
  • 我可以给你用 NSubstitute 测试 MyStateNameService 的代码,不过对起订量了解不多...
  • 没关系,我主要关注概念,使用任何库。我不是那种“给我代码”的用户 ;-)
  • 在编写示例时,我注意到您可能会遇到问题,因为您无法在错误后重用 RPC 代理。在这种情况下,您将不得不注入一个 ProxyFactoryService,这会使事情变得有点复杂。
猜你喜欢
  • 2016-08-24
  • 2012-06-17
  • 1970-01-01
  • 2021-12-02
  • 2020-03-17
  • 2013-02-22
  • 2011-04-11
  • 2020-05-04
  • 1970-01-01
相关资源
最近更新 更多