进行 WCF 服务调用的单元测试方法?
Unit Testing Methods that make WCF Service Call?
第一次尝试任何真正的单元测试。我有一个 WPF 客户端应用程序,它从 WCF 服务中的方法接收数据。这些方法调用是直接从我在客户端应用程序中的视图模型进行的:
public string LoadArticle()
{
MyServiceClient msc = new MyServiceClient();
return Article = msc.GetArticle(_UserName);
}
然后我有一个测试项目,我在其中新建一个视图模型然后调用我的方法:
[TestMethod]
public void LoadArticleTestValid()
{
var articleViewModel = new ArticleViewModel("Thomas");
string userName = "Thomas";
string expected = "Article 1";
var actual = articleViewModel.LoadArticle(userName);
etc.
}
显然此测试将失败,因为客户端应用程序无法访问服务以调用 LoadArticle
。如何解决这种情况?我是使用依赖注入并将某种 IMyService 接口传递给构造函数而不是在 ViewModel 中创建 MyServiceClient 还是以某种方式模拟服务?
是的,我认为你是对的我会建议 IMyService 的构造函数参数,你可以使用它来将模拟注入到对象中以进行测试。
更进一步!我建议不要使用自动生成的服务客户端。如果您将代码复制并粘贴到您自己的 class 中,您可以使其实现 IMyService 并有效地隐藏它使用 WCF 的事实,直接进入数据库或者是来自真实代码的模拟对象。
这将允许您将 Mock 注入 WPF 以进行 UI 测试
这是问题所在:
MyServiceClient msc = new MyServiceClient();
这在 ArticleViewModel
和 MyServiceClient
之间创建了紧密耦合。为了单元测试 just ArticleViewModel
这个依赖需要被模拟。如果有 IMyServiceClient
那么你会把它提供给 class:
public ArticleViewModel
{
private IMyServiceClient ServiceClient { get; set; }
public ArticleViewModel(IMyServiceClient serviceClient)
{
this.ServiceClient = serviceClient;
}
// etc.
}
然后 class 中的代码不会创建新的服务客户端,它只会使用 属性.
中的那个
然后在单元测试中,您将创建 IMyServiceClient
的模拟,在该模拟上定义预期行为,并将其提供给被测试的对象。你如何做到这一点取决于模拟库。 Rhino Mocks 中的一个简单示例可能如下所示:
// arrange
var serviceClient = MockRepository.GenerateMock<IMyServiceClient>();
serviceClient.Stub(c => c.GetArticle(Arg<string>.Is.Anything)).Return("Article 1");
var model = new ArticleViewModel(serviceClient);
// act
var result = model.LoadArticle("Thomas");
// assert
Assert.AreEqual("Article 1", result);
这里的想法是单元测试只测试 LoadArticle
方法,而不是该方法调用的依赖项。这些依赖项提供了预期的行为,并根据这些预期的行为检查结果。
注意: 没有什么可以阻止单元测试提供 实际 实施 MyServiceClient
以及,而不是嘲笑。单元测试项目只需要该服务的配置即可工作。 (单元测试项目是应用程序宿主,它们可以有 App.config
个文件。)这将是一个集成测试而不是单元测试,但可以对结果进行相同的断言。
第一次尝试任何真正的单元测试。我有一个 WPF 客户端应用程序,它从 WCF 服务中的方法接收数据。这些方法调用是直接从我在客户端应用程序中的视图模型进行的:
public string LoadArticle()
{
MyServiceClient msc = new MyServiceClient();
return Article = msc.GetArticle(_UserName);
}
然后我有一个测试项目,我在其中新建一个视图模型然后调用我的方法:
[TestMethod]
public void LoadArticleTestValid()
{
var articleViewModel = new ArticleViewModel("Thomas");
string userName = "Thomas";
string expected = "Article 1";
var actual = articleViewModel.LoadArticle(userName);
etc.
}
显然此测试将失败,因为客户端应用程序无法访问服务以调用 LoadArticle
。如何解决这种情况?我是使用依赖注入并将某种 IMyService 接口传递给构造函数而不是在 ViewModel 中创建 MyServiceClient 还是以某种方式模拟服务?
是的,我认为你是对的我会建议 IMyService 的构造函数参数,你可以使用它来将模拟注入到对象中以进行测试。
更进一步!我建议不要使用自动生成的服务客户端。如果您将代码复制并粘贴到您自己的 class 中,您可以使其实现 IMyService 并有效地隐藏它使用 WCF 的事实,直接进入数据库或者是来自真实代码的模拟对象。
这将允许您将 Mock 注入 WPF 以进行 UI 测试
这是问题所在:
MyServiceClient msc = new MyServiceClient();
这在 ArticleViewModel
和 MyServiceClient
之间创建了紧密耦合。为了单元测试 just ArticleViewModel
这个依赖需要被模拟。如果有 IMyServiceClient
那么你会把它提供给 class:
public ArticleViewModel
{
private IMyServiceClient ServiceClient { get; set; }
public ArticleViewModel(IMyServiceClient serviceClient)
{
this.ServiceClient = serviceClient;
}
// etc.
}
然后 class 中的代码不会创建新的服务客户端,它只会使用 属性.
中的那个然后在单元测试中,您将创建 IMyServiceClient
的模拟,在该模拟上定义预期行为,并将其提供给被测试的对象。你如何做到这一点取决于模拟库。 Rhino Mocks 中的一个简单示例可能如下所示:
// arrange
var serviceClient = MockRepository.GenerateMock<IMyServiceClient>();
serviceClient.Stub(c => c.GetArticle(Arg<string>.Is.Anything)).Return("Article 1");
var model = new ArticleViewModel(serviceClient);
// act
var result = model.LoadArticle("Thomas");
// assert
Assert.AreEqual("Article 1", result);
这里的想法是单元测试只测试 LoadArticle
方法,而不是该方法调用的依赖项。这些依赖项提供了预期的行为,并根据这些预期的行为检查结果。
注意: 没有什么可以阻止单元测试提供 实际 实施 MyServiceClient
以及,而不是嘲笑。单元测试项目只需要该服务的配置即可工作。 (单元测试项目是应用程序宿主,它们可以有 App.config
个文件。)这将是一个集成测试而不是单元测试,但可以对结果进行相同的断言。