单元测试SOA WCF系统......发现难以获得良好的覆盖率

时间:2010-03-01 23:37:40

标签: wcf unit-testing soa

我们目前正在用基于.NET3.5的现代SOA WCF系统取代已有20年历史的基于C的系统。我们的行业需要严格的测试,包括良好的自动化单元测试覆盖率我们遇到了问题,但是将我们的SOA系统单元测试到接近基于C的系统进行单元测试的程度。

最大的问题是系统中的大多数方法实际上都依赖于跨服务边界调用代码,例如我们是大量数据驱动但我们不直接在我们的系统中访问数据库:我们调用WCF数据访问服务。

在visual studio中运行任何单元测试几乎是不可能的,因为几乎任何事情都会导致某种类型的跨服务调用。如果它不是数据访问其他服务之一。我估计我们可以获得大约5%的报道。

我看到很多人都在努力测试SOA,所以我认为这并不是我们所独有的。问题是QA会质疑我们为什么不对系统进行单元测试。

老实说,我认为VSTS单元测试更像是回归测试,而不是验证(适合使用)工具。单元测试SOA有哪些选择?在人们的经验中实现良好的覆盖是否现实?有没有办法模拟数据访问服务(或任何服务:注意我们不使用WCF代理)或者我们是否必须向QA解释单元测试能力在过去20年中倒退了......

欢迎任何形式的建议,我想这是一个普遍的意见问题。

3 个答案:

答案 0 :(得分:5)

我不得不说,对SOA进行单元测试很像是对其他任何东西进行单元测试。如果有什么它应该更容易,因为它迫使你隔离依赖。

单元测试不应该通常跨越服务边界。实际上,服务的想法是它完全独立且不透明。您直接测试服务 - 不是通过WCF通道,而是通过单元测试组成服务的实际类。一旦您测试了服务本身(您应该能够获得接近100%的覆盖率),您就不需要将其纳入客户端测试中。

对于客户端单元测试,您可以模拟服务。 WCF实际上让你很容易,因为每个WCF客户端都实现了一个接口;如果您通常在代码中使用FooServiceFooServiceSoapClient,请将其更改为使用代理类实现的相应IFooServiceFooServiceSoap。然后,您可以编写自己的MockFooService来实现相同的接口,并在客户端测试中使用它。

有时候在这里绊倒人们的部分原因是服务可以根据具体的消息做出截然不同的事情。但是,涉及服务接口的客户端测试通常应该只测试一个或两个特定的消息每个测试,因此很容易使用工具模拟给定客户端测试所需的确切请求/响应比如Rhino Mocks

Duplex有点棘手,但请记住,双工服务也应该基于接口;即使MSDN example引入了ICalculatorDuplexCallback。回调将是接口,因此就像您可以在客户端模拟服务方法一样,您可以在服务端模拟客户端回调。只需要用于服务单元测试的模拟/假回调。

马克·西曼(Mark Seeman)有一篇关于Unit-Testing Duplex WCF Clients的博文,其中包括示例代码和所有内容。你应该给它一个阅读,我想它会帮助你在这里。

答案 1 :(得分:2)

听起来您现在正在进行的测试是integration tests或系统测试。测试方法调用外部源的地方。要真正对服务执行单元测试,您需要以某种方式抽象外部调用,以便您可以模拟(例如moq)或存根调用该服务。

例如紧密耦合到数据访问服务的代码:

public class SomeSOA
{
 public bool DoSomeDataAccess()
 {
  //call the real data service
  DataService dataService = new DataService()
  int getANumber = dataService.GetANumber();
  return getANumber == 2;
 }
}

稍微重构以减少与DataService的耦合

public class SomeSOA
{
 IDataService _dataService;
 public SomeSOA(IDataService dataService)
{
  _dataService = dataService;
}
public SomeSOA() :this(new DataServiceWrapper()){}
 public bool DoSomeDataAccess()
 {
  int getANumber = _dataService.GetANumber();
  return getANumber == 2;
 }
}

public DataServiceWrapper : IDataService
{
  public int GetANumber()
  {
   // call the real data service
  }
}

现在使用重新分解的代码,您可以修改测试以使用可以在不调用真实DataService的情况下返回预期结果的存根。

[TestMethod]
public void GetANumber_WithAValidReturnedNumber_ReturnsTure()
{

  IDataService dataService = new DataServiceFake();
  SomeSOA someSoa = new SomeSOA(dataService);
  Assert.IsTrue(someSoa.DoSomeDataAccess();
}

public class DataServiceFake :IDataService
{
  public int DoSomeDataAccess()
  {
    //return a fake result from the dataService.
    return 2;
  }
}

现在授予所有这些只是伪代码,但是将服务与DataAccessSerive的实际插入分离将允许您对代码进行单元测试,而不依赖于真正的DataAccessService来使它们正确执行。

希望这有帮助并且有意义!

答案 2 :(得分:1)

这是我的建议:远离“单元测试”范例,并开展一系列集成测试。

我假设您的系统有一个调用服务的前端。

编写一个实际连接到正在运行的服务的测试套件(显然在您的测试环境中),并像前端那样进行相同的调用序列。

您的测试环境将针对空的测试数据库运行最新的服务。就像单元测试一样,每个测试都会调用填充测试数据的调用,调用功能,测试可见信息现在是否匹配,然后再次清除数据库。

您可能必须通过根据请求清除数据库来创建一个服务集成测试的其他服务。 (显然,你实际上不会部署那个......)

虽然它们不是“单元测试”,但您将获得全面覆盖。