big*_*oot 4 c# unit-testing moq
我试图模拟对服务器的调用,并验证测试的代码调用正确的方法.代码结构如下:
public interface IServerAdapter
{
void CallServer(Action<IServerExposingToClient> methodToCall, out bool serverCalled);
object CallServer(Func<IServerExposingToClient, object> methodToCall, out bool serverCalled);
}
public interface IServerExposingToClient
{
Resource GetResource(string id);
void AddResource(Resource resource);
}
Run Code Online (Sandbox Code Playgroud)
我正在测试的代码访问服务器上的一个实现IServerAdapter并调用IServerExposingToClient方法.这样做的原因是我们不希望在类中实现每个方法(它们中有很多方法)IServerExposingToClient.由于这是在代理上调用的,因此它在我们的代码中运行良好.
在服务器上调用方法是这样的:
_mainViewModel.ServerAdapter.CallServer(m => m.AddResource(resource), out serverCalled);
Run Code Online (Sandbox Code Playgroud)
现在的问题是测试和嘲笑.我需要断言AddResource在服务器上调用了method().在out serverCalled(问题1),以确保这样的逻辑,因为它应该呼叫者流动电话做了它对服务器.
当我使用以下Moq设置时,我可以断言在服务器上调用了一些方法:
Mock<IServerAdapter> serverAdapterMock = new Mock<IServerAdapter>();
bool serverCalled;
bool someMethodCalled = false;
serverAdapterMock.Setup(c => c.CallServer(It.IsAny<Action<IServerExposingToClient>>(), out serverCalled)).Callback(() => someMethodCalled = true);
// assign serverAdapterMock.Object to some property my code will use
// test code
Assert.IsTrue(someMethodCalled, "Should have called method on server.");
Run Code Online (Sandbox Code Playgroud)
正如测试所说,我可以断言在服务器上调用了一些方法.问题是我不知道调用了哪种方法.在某些方法中,我想要测试的逻辑可以根据条件采用不同的路径,对于某些情况,多个路径可能会导致服务器调用.因此,我需要知道调用哪个方法,以便在测试中得到正确的断言(问题2).
serverCalled需要将变量设置为匹配IServerAdapter mock上方法调用的签名.我也非常希望能够在一些回调中设置该变量,或者让我正在测试的代码的逻辑以它应该的方式流动的任何东西(问题1).由于它现在的工作方式,因此不会通过模拟设置来设置serverCalled.
主要问题是不知道针对服务器调用了哪种方法.我曾尝试使用Match来检查委托方法的名称,但没有使用sigar.
serverAdapterMock.Setup(c => c.CallServer(Match.Create<Action<IServerExposingToClient>>( x => IsAddResource(x)), out serverCalled)).Callback(() => someMethodCalled = true);
Run Code Online (Sandbox Code Playgroud)
当IsAddResource被调用时,该功能并不是指AddResource,只有在创建它,什么说法它被称为用.
有谁知道如何检查调用哪种方法?
对于另一个问题out serverCalled,您可以争辩说该void方法可以bool改为,并且null如果我们没有与服务器的连接,则另一个方法可以返回(最后一个参数将是不明确的,因为null可能意味着对象不存在,或服务器不可用).
我非常希望能找到解决这两个问题的建议.
提前致谢
问题一:
正如您所指出的,这里的回调将是理想的.不幸的是,因为你的方法签名有一个out参数,所以它目前不能被Moq拦截.Moq论坛中有一篇与您关注的内容类似的帖子.没有任何迹象表明它会得到解决.
如果您愿意更改方法签名,请考虑删除out参数 - 无论如何它们都有点气味.如果您在服务器不可用时抛出异常,事情就会简单得多.获得该出的有(双关语意)会打开你的回调来处理你的第二个问题.
问题二:
考虑将方法签名更改为Expression <Action <IServerExposingToClient >>.我意识到那里有很多尖括号,但是Expression在语法上等同于Action <T>(你不必更改你的调用代码)并允许你的Callback遍历代码表达式树并得到你的名字调用方法.
您可以使用以下内容获取方法的名称:
public string GetMethodName(Expression<Action<IServerExposingToClient>> exp)
{
return ((ExpressionMethodCall)exp.Body).Method.Name;
}
Run Code Online (Sandbox Code Playgroud)
你现在有足够的武器库去追求你的模拟.您可以编写一个记录方法调用名称的回调,也可以编写匹配器来帮助定义调用方法时的行为.
例如:
[Test]
public void WhenTheViewModelIsLoaded_TheSystem_ShouldRecordOneNewResource()
{
// arrange
var serverAdapterMock = new Mock<IServerAdapter>();
var subject = new SubjectUnderTest( serverAdapterMock.Object );
// act
subject.Initialize();
// assert
serverAdapterMock.Verify( c => c.CallServer( IsAddResource() ), Times.Exactly(1));
}
static Expression<Action<IServerExposedToClient>> IsAddResource()
{
return Match.Create<Expression<Action<IServerExposedToClient>>>(
exp => GetMethodName(exp) == "AddResource");
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4507 次 |
| 最近记录: |