单元测试Web服务的推荐模式

时间:2012-03-06 16:05:55

标签: wcf web-services unit-testing rest soa

我们即将开始构建面向服务的框架(SOA),这肯定会涉及大量的粒度Web服务(WCF中的REST)。我们在对客户端和服务器端代码库进行单元测试时非常自律,但是我们在单元测试Web服务方面没有太多经验。我们真的在寻找关于应该在哪里编写测试的指导,以及在单元测试我们的服务时使用什么方法的建议。

我们是否应该编写发出http请求的测试并声明响应是他们应该的?我们是否应该只关注测试服务方法本身的内部逻辑而不是担心测试实际的请求?或者我们应该两个都做?我们应该测试什么还有其他建议吗?

我们真的在寻找一些解释和指导,并且非常感谢我们能得到的任何建议。

2 个答案:

答案 0 :(得分:11)

我发现测试Web服务,特别是WCF客户端和服务器,在以下场景中对常规单元测试很有用:

  1. 验收测试,您希望对整个服务进行黑盒测试,并在四肢进行瞄准。
  2. 测试特定的WCF线路,扩展,行为等
  3. 测试您的界面和数据成员是否设置正确。
  4. 大多数时候,我尝试使用基本http的基本设置,并在代码中连接所有内容。除非我是集成或验收测试,否则我不会针对服务器测试客户端,而是我模拟其中一个,以便我可以单独测试另一个。以下是我如何测试WCF客户端和服务的示例:

    public static ServiceHost CreateServiceHost<TServiceToHost>(TServiceToHost serviceToHost, Uri baseAddress, string endpointAddress)
    {
        var serviceHost = new ServiceHost(serviceToHost, new[] { baseAddress });
    
        serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
        serviceHost.Description.Behaviors.Find<ServiceBehaviorAttribute>().InstanceContextMode = InstanceContextMode.Single;
    
        serviceHost.AddServiceEndpoint(typeof(TServiceToHost), new BasicHttpBinding(), endpointAddress);
    
        return serviceHost;
    }
    
    //Testing Service
    
    [TestFixture]
    class TestService
    {
        private ServiceHost myServiceUnderTestHost;
        private ChannelFactory<IMyServiceUnderTest> myServiceUnderTestProxyFactory;
        [SetUp]
        public void SetUp()
        {
            IMyServiceUnderTest myServiceUnderTest = new MyServiceUnderTest();
            myServiceUnderTestHost = CreateServiceHost<IMyServiceUnderTest>(myServiceUnderTest, new Uri("http://localhost:12345"), "ServiceEndPoint");
            myServiceUnderTestHost.Open();
    
            myServiceUnderTestProxyFactory = new ChannelFactory<IMyServiceUnderTest>(new BasicHttpBinding(), new EndpointAddress("http://localhost:12345/ServiceEndPoint")); 
        }
    
        [TearDown]
        public void TearDown()
        {
            myServiceUnderTestProxyFactory.Close();
            myServiceUnderTestHost.Close();
        }
    
        [Test]
        public void SomeTest() 
        {
            IMyServiceUnderTest serviceProxy = myServiceUnderTestProxyFactory.CreateChannel();
    
            serviceProxy.SomeMethodCall();
        }
    }
    
    //Testing Client
    
    [TestFixture]
    class TestService
    {
        private ServiceHost myMockedServiceUnderTestHost;
        private IMyServiceUnderTest myMockedServiceUnderTest;
    
        [SetUp]
        public void SetUp()
        {
            myMockedServiceUnderTest = Substitute.For<IMyServiceUnderTest>(); //Using nsubstitute
            myServiceUnderTestHost = CreateServiceHost<IMyServiceUnderTest>(myMockedServiceUnderTest, new Uri("http://localhost:12345"), "ServiceEndPoint");
            myServiceUnderTestHost.Open();
        }
    
        [TearDown]
        public void TearDown()
        {
            myServiceUnderTestHost.Close();
        }
    
        [Test]
        public void SomeTest() 
        {
            //Create client and invoke methods that will call service
            //Will need some way of configuring the binding
            var client = new myClientUnderTest();
    
            client.DoWork();
    
            //Assert that method was called on the server
            myMockedServiceUnderTest.Recieved().SomeMethodCall();
        }
    }
    

    注意

    我忘了提到如果你想使用任何使用城堡动态代理的东西来模拟WCF服务,那么你需要阻止将ServiceContractAttribute复制到模拟中。我有一个blog post,但基本上你将属性注册为一个,以防止在创建模拟之前进行复制。

    Castle.DynamicProxy.Generators.AttributesToAvoidReplicating
      .Add<ServiceContractAttribute>();
    

答案 1 :(得分:3)

基本上我认为你需要有两部分测试策略。

第一部分是真正的单元测试,它将涉及完全独立于任何Web请求测试类... 因为单元测试的主要定义是在不需要额外环境或设置的情况下运行的测试除了测试本身的那些。

因此,您将创建单元测试项目,在其中您将实例化WCF服务的代码类,以确保逻辑正确,这与测试其余类的方式非常相似。

第二部分是一组集成测试,它将以端到端的方式测试您的应用程序。当然,在这里你需要整个辣酱玉米饼馅,网络服务器,数据库等等。

通过这种方式,您可以了解您的逻辑是否准确以及您的应用程序是否正常工作。