【问题标题】:Recommended patterns for unit testing web services单元测试 Web 服务的推荐模式
【发布时间】:2012-03-24 03:35:12
【问题描述】:

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    第二部分是一组集成测试,它将以端到端的方式测试您的应用程序。当然,这里你需要整个 enchilada、Web 服务器、数据库等等。

    这样您就知道您的逻辑是准确的,并且您的应用程序也可以正常工作。

    【讨论】:

      【解决方案2】:

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

      1. 验收测试,您希望对整个服务进行黑盒测试并在极端情况下进行测试。
      2. 测试特定的 WCF 连接、扩展、行为等。
      3. 测试您的界面和数据成员是否设置正确。

      大多数时候,我尝试使用带有基本 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>();
      

      【讨论】:

        猜你喜欢
        • 2011-12-30
        • 2011-02-03
        • 1970-01-01
        • 2011-04-30
        • 1970-01-01
        • 1970-01-01
        • 2015-05-04
        • 1970-01-01
        • 2012-03-20
        相关资源
        最近更新 更多