简体   繁体   中英

Unit testing / mocking XML-RPC.net calls

I'm developing an application that uses CookComputing XML-RPC.net

My question is how to unit test methods that call an external rpc method.

If we take the example on the site:

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

How can we effectively test the result of IStateName without actually hitting http://www.cookcomputing.com/xmlrpcsamples/RPC2.ashx

I suppose a good start would be a constructor on MyStateNameService taking an IStateName, and passing in a fake (or mocked?) instance on IStateName...

I'm interested in testing it for actual content - for example faking up the response from the endpoint, and returning that somehow, not just verifying that GetStateName calls the service...

Edit

I'm not trying to test the content of the service as such, moreover what my classes do with it.

So, for example, say the response is:

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

I'd want to 'fake' that response some how to test that MyStateNameService.GetStateName actually returned 'My State Name'

Your problem lies in the Singleton Pattern applied here.

XmlRpcProxyGen.Create<IStateName>();

So your idea with using Dependency Injection (By Constructor) is a good start. (Do you use an IoC container?)

Next is to create a Mock/Fake/Stub for the IStateName service. This can be achieved by many ways.

Using a dynamic mocking system may save you some work, but you need to learn their usage.

Classic AAA testing example for using NUnit, NSubstitute and a modified MyStateNameService :

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 ;) 
    */


  }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM