模型-视图-视图模型&;WCF-WCF是模型吗?
我只是在学习Model/View/ViewModel模式及其变体(DataModel/View/ViewModel或Model/View/Presenter) 我想知道的是:如果我将此模式用于WCF服务,该服务是模型(DataModel),还是需要一个单独的模型来封装WCF服务层 当我使用WCF作为数据模型时,如果不模拟整个WCF服务,我的ViewModel是不可测试的,因为对WCF的调用需要管理连接。此ViewModel中的调用如下所示:模型-视图-视图模型&;WCF-WCF是模型吗?,wcf,mvvm,stress-testing,Wcf,Mvvm,Stress Testing,我只是在学习Model/View/ViewModel模式及其变体(DataModel/View/ViewModel或Model/View/Presenter) 我想知道的是:如果我将此模式用于WCF服务,该服务是模型(DataModel),还是需要一个单独的模型来封装WCF服务层 当我使用WCF作为数据模型时,如果不模拟整个WCF服务,我的ViewModel是不可测试的,因为对WCF的调用需要管理连接。此ViewModel中的调用如下所示: List<Sam.Alyza.WcfInterf
List<Sam.Alyza.WcfInterface.Website> rc = null;
Service<Sam.Alyza.WcfInterface.IServiceWebsites>.Use(alyzaSvc =>
{
rc = new List<Sam.Alyza.WcfInterface.Website>(alyzaSvc.GetSites());
});
List<Sam.Alyza.WcfInterface.Website> rc = new List<Sam.Alyza.WcfInterface.Website>(_datamodel.GetSites());
interface IClientFactory
{
TClient CreateClient<TClient>();
}
class ClientFactory : IClientFactory
{
TClient CreateClient<TClient>()
{
var channelFactory = new ChannelFactory<TClient>("AlyzaServiceEndpoint");
var proxy = (TClient)channelFactory.CreateChannel();
return proxy;
}
}
public ViewModel
{
public ViewModel(IClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
private void DoWcfStuff()
{
using (var proxy = _clientFactory.CreateClient<IClientChannel>())
{
var result = proxy.GetThings();
}
}
}
public ViewModelTests
{
public void Setup()
{
_mockFactory = new MockClientFactory();
_viewModel = new ViewModel(_mockFactory);
}
[Test]
public void Test()
{
var testResult = new Result();
var mockClient = _mockFactory.CreateClient<IClientChannel>();
mockClient.SetResultForGetThings(testResult);
// put the viewmodel through its paces.
}
private class MockClientFactory : IClientFactory
{
MockClient _mockClient;
public MockClientFactory()
{
_mockClient = new MockClient();
}
public TClient CreateClient<TClient>()
{
if (typeof(TClient) == typeof(IClientChannel))
{
return _mockClient;
}
}
}
private class MockClient : IClientChannel
{
void SetupGetThingsResult(Result result)
{
_result = result;
}
Result GetThings()
{
return _result;
}
}
}
List rc=null;
Service.Use(alyzaSvc=>
{
rc=新列表(alyzaSvc.GetSites());
});
为了使ViewModel可测试,我尝试添加一个单独的数据模型来抽象WCF连接。在此之后,ViewModel是可测试的,调用如下所示:
List<Sam.Alyza.WcfInterface.Website> rc = null;
Service<Sam.Alyza.WcfInterface.IServiceWebsites>.Use(alyzaSvc =>
{
rc = new List<Sam.Alyza.WcfInterface.Website>(alyzaSvc.GetSites());
});
List<Sam.Alyza.WcfInterface.Website> rc = new List<Sam.Alyza.WcfInterface.Website>(_datamodel.GetSites());
interface IClientFactory
{
TClient CreateClient<TClient>();
}
class ClientFactory : IClientFactory
{
TClient CreateClient<TClient>()
{
var channelFactory = new ChannelFactory<TClient>("AlyzaServiceEndpoint");
var proxy = (TClient)channelFactory.CreateChannel();
return proxy;
}
}
public ViewModel
{
public ViewModel(IClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
private void DoWcfStuff()
{
using (var proxy = _clientFactory.CreateClient<IClientChannel>())
{
var result = proxy.GetThings();
}
}
}
public ViewModelTests
{
public void Setup()
{
_mockFactory = new MockClientFactory();
_viewModel = new ViewModel(_mockFactory);
}
[Test]
public void Test()
{
var testResult = new Result();
var mockClient = _mockFactory.CreateClient<IClientChannel>();
mockClient.SetResultForGetThings(testResult);
// put the viewmodel through its paces.
}
private class MockClientFactory : IClientFactory
{
MockClient _mockClient;
public MockClientFactory()
{
_mockClient = new MockClient();
}
public TClient CreateClient<TClient>()
{
if (typeof(TClient) == typeof(IClientChannel))
{
return _mockClient;
}
}
}
private class MockClient : IClientChannel
{
void SetupGetThingsResult(Result result)
{
_result = result;
}
Result GetThings()
{
return _result;
}
}
}
List rc=新列表(_datamodel.GetSites());
问题:现在需要测试的大部分代码都已经转移到了数据模型中,这同样需要测试WCF。ViewModel中剩下的是一个薄壳,可以进行测试。但是由于主代码移到了数据模型中,因此测试ViewModel是毫无用处的
因此,在我看来,使用WCF向View/ViewModel应用程序添加单独的数据模型层确实增加了很多工作,但可测试性并没有得到任何改善。Woot,经过两天的努力,我找到了一个我可以接受的解决方案: 如上面的代码示例所示,我使用这个helper类来管理我的WCF连接(因为正确处理了关闭与中止):
public委托void-UseServiceDelegate(T-proxy);
公共静态类服务
{
公共静态通道工厂_ChannelFactory;
公共静态无效使用(UseServiceDelegate代码块)
{
如果(_channelFactory==null)
_channelFactory=新的channelFactory(“AlyzaServiceEndpoint”);
IClientChannel代理=(IClientChannel)_channelFactory.CreateChannel();
布尔成功=假;
尝试
{
代码块((T)代理);
proxy.Close();
成功=真实;
}
最后
{
如果(!成功)
{
proxy.Abort();
}
}
}
}
如我的问题所示,这是在我的ViewModel中使用此类的方式:
Service<Sam.Alyza.WcfInterface.IServiceWebsites>.Use(alyzaSvc =>
{
rc = new List<Sam.Alyza.WcfInterface.Website>(alyzaSvc.GetSites());
});
Service.Use(alyzaSvc=>
{
rc=新列表(alyzaSvc.GetSites());
});
要模拟WCF接口,我需要创建并托管一个模拟WCF服务,更改所有连接字符串。只需添加一些测试就可以完成大量工作
我找到了一个更简单的方法:
创建实现接口的模拟服务很简单:
public class MockWebsiteService : WcfInterface.IServiceWebsites
{
internal List<Sam.Alyza.WcfInterface.Website> _websites = new List<Sam.Alyza.WcfInterface.Website>();
internal int _GetSitesCallCount;
IEnumerable<Sam.Alyza.WcfInterface.Website> Sam.Alyza.WcfInterface.IServiceWebsites.GetSites()
{
_GetSitesCallCount++;
return _websites;
}
}
公共类MockWebsiteService:WcfInterface.IServiceWebsites
{
内部列表_网站=新列表();
内部int\u getsitescalcount;
IEnumerable Sam.Alyza.WcfInterface.IServiceWebsites.GetSites()
{
_GetSitesCallCount++;
返回(u)网站;;
}
}
唯一的问题是:如何让ViewModel调用这个模拟类而不是服务?解决方案:Service.Use()管理连接。通过添加覆盖连接管理的功能,我能够将我自己的WCF模拟对象偷偷带到服务中。Use()。
为此,我需要一种使Service.Use()调用WCF以外的东西的方法(请参阅#DEBUG部分):
公共静态类服务
{
#如果调试
公共静态T DebugOverride=默认值(T);
#恩迪夫
公共静态通道工厂_ChannelFactory;
公共静态无效使用(UseServiceDelegate代码块)
{
#如果调试
如果(!Object.Equals(DebugOverride,默认值(T)))
{
代码块(DebugOverride);
返回;
}
#恩迪夫
如果(_channelFactory==null)
_channelFactory=新的channelFactory(“AlyzaServiceEndpoint”);
IClientChannel代理=(IClientChannel)_channelFactory.CreateChannel();
布尔成功=假;
尝试
{
代码块((T)代理);
proxy.Close();
成功=真实;
}
最后
{
如果(!成功)
{
proxy.Abort();
}
}
}
}
通过将这个测试钩子添加到服务中,我能够在测试中潜入任何实现T的对象:
MockWebsiteService mockmodel = new MockWebsiteService();
Service<WcfInterface.IServiceWebsites>.DebugOverride = mockmodel;
// run my tests here
MockWebsiteService mockmodel=新建MockWebsiteService();
Service.DebugOverride=mockmodel;
//在这里运行我的测试
对我来说,这是模拟WCF服务的一个非常好的方法
PS:我知道由于#if调试,测试不会在发行版中编译。如果您愿意的话,就把它们踢出去。我们使用依赖注入来解决这个问题,将服务客户机(或者服务客户机的工厂)注入到ViewModel中。大概是这样的:
List<Sam.Alyza.WcfInterface.Website> rc = null;
Service<Sam.Alyza.WcfInterface.IServiceWebsites>.Use(alyzaSvc =>
{
rc = new List<Sam.Alyza.WcfInterface.Website>(alyzaSvc.GetSites());
});
List<Sam.Alyza.WcfInterface.Website> rc = new List<Sam.Alyza.WcfInterface.Website>(_datamodel.GetSites());
interface IClientFactory
{
TClient CreateClient<TClient>();
}
class ClientFactory : IClientFactory
{
TClient CreateClient<TClient>()
{
var channelFactory = new ChannelFactory<TClient>("AlyzaServiceEndpoint");
var proxy = (TClient)channelFactory.CreateChannel();
return proxy;
}
}
public ViewModel
{
public ViewModel(IClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
private void DoWcfStuff()
{
using (var proxy = _clientFactory.CreateClient<IClientChannel>())
{
var result = proxy.GetThings();
}
}
}
public ViewModelTests
{
public void Setup()
{
_mockFactory = new MockClientFactory();
_viewModel = new ViewModel(_mockFactory);
}
[Test]
public void Test()
{
var testResult = new Result();
var mockClient = _mockFactory.CreateClient<IClientChannel>();
mockClient.SetResultForGetThings(testResult);
// put the viewmodel through its paces.
}
private class MockClientFactory : IClientFactory
{
MockClient _mockClient;
public MockClientFactory()
{
_mockClient = new MockClient();
}
public TClient CreateClient<TClient>()
{
if (typeof(TClient) == typeof(IClientChannel))
{
return _mockClient;
}
}
}
private class MockClient : IClientChannel
{
void SetupGetThingsResult(Result result)
{
_result = result;
}
Result GetThings()
{
return _result;
}
}
}
接口IClientFactory
{
TClient CreateClient();
}
类ClientFactory:IClientFactory
{
TClient CreateClient()
{
var channelFactory=新的channelFactory(“AlyzaServiceEndpoint”);
var proxy=(TClient)channelFactory.CreateChannel();
返回代理;
}
}
公共视图模型
{
公共视图模型(IClientFactory客户端工厂)
{
_clientFactory=clientFactory;
}
私人文件
{
使用(var proxy=\u clientFactory.CreateClient())
{
var result=proxy.GetThings();
}
}
}
公共视图模型测试
{
公共作废设置()
{
_mockFactory=新的MockClientFactory();
_viewModel=新的viewModel(_mockFactory);
}
[测试]
公开无效测试()
{
var testResult=新结果();
var mockClient=_mockFactory.CreateClient();
mockClient.SetResultForGetThings(testResult);
//对viewmodel进行测试。
}
私有类MockClientFactory:IClientFactory
{
MockClient\u MockClient;
公共MockClientFactory()
{
_mockClient=新的mockClient();
}
公共TClient CreateClient()
{
if(typeof(TClient)=typeof(IClientChannel))
{
返回\u mockClient;
}
}
}
私有类MockClient:IClientChannel
{