在我的项目中,我使用的是:SL5+ MVVM+ Prism + WCF + Rx + Moq + Silverlight 单元测试框架。
我是单元测试的新手,最近开始研究 DI、模式 (MVVM) 等。因此,以下代码有很大的改进空间(如果你这么认为,请随意拒绝我采用的整个方法)。
为了访问我的 WCF 服务,我创建了一个如下所示的工厂类(同样,它可能存在缺陷,但请看一看):
namespace SomeSolution
{
public class ServiceClientFactory:IServiceClientFactory
{
public CourseServiceClient GetCourseServiceClient()
{
var client = new CourseServiceClient();
client.ChannelFactory.Faulted += (s, e) => client.Abort();
if(client.State== CommunicationState.Closed){client.InnerChannel.Open();}
return client;
}
public ConfigServiceClient GetConfigServiceClient()
{
var client = new ConfigServiceClient();
client.ChannelFactory.Faulted += (s, e) => client.Abort();
if (client.State == CommunicationState.Closed) { client.InnerChannel.Open(); }
return client;
}
public ContactServiceClient GetContactServiceClient()
{
var client = new ContactServiceClient();
client.ChannelFactory.Faulted += (s, e) => client.Abort();
if (client.State == CommunicationState.Closed) { client.InnerChannel.Open(); }
return client;
}
}
}
它实现了一个简单的接口(interface),如下所示:
public interface IServiceClientFactory
{
CourseServiceClient GetCourseServiceClient();
ConfigServiceClient GetConfigServiceClient();
ContactServiceClient GetContactServiceClient();
}
在我的虚拟机中,我正在执行上述类的 DI 并使用 Rx 调用 WCF,如下所示:
var client = _serviceClientFactory.GetContactServiceClient();
try
{
IObservable<IEvent<GetContactByIdCompletedEventArgs>> observable =
Observable.FromEvent<GetContactByIdCompletedEventArgs>(client, "GetContactByIdCompleted").Take(1);
observable.Subscribe(
e =>
{
if (e.EventArgs.Error == null)
{
//some code here that needs to be unit-tested
}
},
ex =>
{
_errorLogger.ProcessError(GetType().Name, MethodBase.GetCurrentMethod().Name, ErrorSource.Observable, "", -1, ex);
}
);
client.GetContactByIdAsync(contactid, UserInformation.SecurityToken);
}
catch (Exception ex)
{
_errorLogger.ProcessError(GetType().Name, MethodBase.GetCurrentMethod().Name, ErrorSource.Code, "", -1, ex);
}
现在我想构建单元测试(是的,它不是 TDD)。但我不明白从哪里开始。使用 Moq 我无法模拟 BlahServiceClient。也没有 svcutil 生成的接口(interface)可以提供帮助,因为异步方法不是自动生成的 IBlahService 接口(interface)的一部分。我可能更喜欢扩展(通过部分类等)任何自动生成的类,但我不愿意选择手动构建 svcutil 可以生成的所有代码(坦率地说,考虑到时间和预算)。
有人可以帮忙吗?任何指向正确方向的指针都会对我有很大帮助。
最佳答案
在模拟您的服务客户端时,您实际上是在模拟它实现的接口(interface)之一。所以在你的情况下它可能是 IContactService
.
生成的代码实现了System.ServiceModel.ClientBase<IContactService>
和 IContactService
.您的依赖提供者(在您的情况下是工厂)正在返回 ContactServiceClient
- 将其更改为 IContactService
对于初学者。这将在现在和将来帮助您的 DI。
好的,你已经有了一个抽象工厂,现在它们返回你的服务接口(interface) IContactService
.您现在才使用接口(interface),所以模拟非常简单。
首先对您尝试使用的代码进行一些假设。代码片段提供了抽象工厂和服务客户端的消息。前提是//这里有些代码需要进行单元测试 部分不会与任何其他 交互依赖 然后您希望模拟工厂和服务客户端,以便您的测试仅与方法主体代码隔离。
为了举例,我做了一个调整。您的界面:
public class Contact {
public string Name { get; set; }
}
public interface IContactService {
Contact GetContactById(int contactid);
}
public interface IContactServiceFactory {
IContactService GetContactService();
}
然后你的测试看起来像这样总结:
public void WhateverIsToBeTested_ActuallyDoesWhatItMustDo() {
// Arrange
var mockContactService = new Mock<IContactService>();
mockContactService.Setup(cs => cs.GetContactById(It.IsAny<int>()))
.Returns(new Contact { Name = "Frank Borland" });
var fakeFactory = new Mock<IContactServiceFactory>();
fakeFactory.Setup(f => f.GetContactService())
.Returns(mockContactService.Object);
/* i'm assuming here that you're injecting the dependency intoto your factory via the contructor - but
* assumptions had to be made as not all the code was provided
*/
var yourObjectUnderTest = new MysteryClass(fakeFactory.Object);
// Act
yourObjectUnderTest.yourMysteryMethod();
// Assert
/* something mysterious, but expected, happened */
}
编辑:模拟异步方法
异步生成的方法不是您的服务方法的一部分,而是由 WCF 作为 Client 类的一部分创建的。要将它们模拟为接口(interface),请执行以下操作:
ContactServiceClient
的接口(interface)类(class)。在 VS 中,只需右键单击(在类名上)、重构、提取接口(interface)。并且只选择适用的方法。 ContactServiceClient
类是部分的,所以创建一个 新建类文件并重新定义 ContactServiceClient 类以实现新的 IContactServiceClient
刚刚提取的界面。public partial class ContactServiceClient : IContactServiceClient {
}
像这样,现在客户端类也使用选定的异步方法实现新接口(interface)。当刷新您的服务接口(interface)并重新生成服务类时 - 您不必重新提取接口(interface),因为您已经使用接口(interface)引用创建了一个单独的部分类。
public interface IContactServiceClientFactory {
IContactServiceClient GetContactServiceClient();
}
关于wcf - 如何使用 Moq 模拟 WCF 客户端?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14062508/