使用Moqvalidation参考参数的值

我刚刚切换到Moq并遇到了问题。 我正在测试一个创建业务对象的新实例的方法,从用户输入值设置对象的属性,并调用方法(SaveCustomerContact)来保存新对象。 业务对象作为ref参数传递,因为它通过远程处理层。 我需要测试传递给SaveCustomerContact的对象是否按预期设置了所有属性,但由于它在控制器方法中被实例化为new,我似乎无法这样做。

public void AddContact() { var contact = new CustomerContact() { CustomerId = m_model.CustomerId }; contact.Name = m_model.CustomerContactName; contact.PhoneNumber = m_model.PhoneNumber; contact.FaxNumber = m_model.FaxNumber; contact.Email = m_model.Email; contact.ReceiveInvoiceFlag = m_model.ReceiveInvoiceFlag; contact.ReceiveStatementFlag = m_model.ReceiveStatementFlag; contact.ReceiveContractFlag = m_model.ReceiveContractFlag; contact.EmailFlag = m_model.EmailFlag; contact.FaxFlag = m_model.FaxFlag; contact.PostalMailFlag = m_model.PostalMailFlag; contact.CustomerLocationId = m_model.CustomerLocationId; RemotingHandler.SaveCustomerContact( ref contact ); } 

这是测试:

 [TestMethod()] public void AddContactTest() { int customerId = 0; string name = "a"; var actual = new CustomerContact(); var expected = new CustomerContact() { CustomerId = customerId, Name = name }; model.Setup( m => m.CustomerId ).Returns( customerId ); model.SetupProperty( m => model.CustomerContactName, name ); model.SetupProperty( m => m.PhoneNumber, string.Empty ); model.SetupProperty( m => m.FaxNumber, string.Empty ); model.SetupProperty( m => m.Email, string.Empty ); model.SetupProperty( m => m.ReceiveInvoiceFlag, false ); model.SetupProperty( m => m.ReceiveStatementFlag, false ); model.SetupProperty( m => m.ReceiveContractFlag, false ); model.SetupProperty( m => m.EmailFlag, false ); model.SetupProperty( m => m.FaxFlag, false ); model.SetupProperty( m => m.PostalMailFlag, false ); model.SetupProperty( m => m.CustomerLocationId, 0 ); remote .Setup( r => r.SaveCustomerContact( ref actual ) ) .Callback( () => Assert.AreEqual( actual, expected ) ); target.AddContact(); } 

这只是获得该参数的许多尝试中最近的一次。 作为参考,实际值不会从其初始(构造)状态改变。

在目标调用失败后移动Assert.AreEqual(expected,actual)。 如果我将.Verifiable()添加到设置而不是.CallBack然后在目标之后调用remote.Verify(或者,我假设,将mock设置为strict)它总是失败,因为我在测试中提供的参数不是与在控制器方法中创建的实例相同的实例。

我正在使用Moq 3.0.308.2。 任何关于如何测试这个的想法将不胜感激。 谢谢!

我无法为您提供一个精确的解决方案,但另一种方法是隐藏适配器后面的pass-by-ref语义,该适配器按值获取参数并将其转发给RemotingHandler。 这将更容易模拟,并将从界面中删除“ref”疣(我总是怀疑ref参数:-))

编辑:

或者您可以使用存根而不是模拟,例如:

 public class StubRemotingHandler : IRemotingHandler { public CustomerContact savedContact; public void SaveCustomerContact(ref CustomerContact contact) { savedContact = contact; } } 

您现在可以检查测试中保存的对象:

 IRemotingHandler remote = new StubRemotingHandler(); ... //pass the stub to your object-under-test ... target.AddContact(); Assert.AreEqual(expected, remote.savedContact); 

你还在评论中说:

我不想开始包装后端的随机位的先例,这样我就可以更轻松地编写测试了

我认为这正是你需要设定的先例! 如果您的代码不可测试,那么您将继续努力测试它。 使测试更容易,并增加您的覆盖范围。

最新版本的Moq支持此方案。

摘自http://code.google.com/p/moq/wiki/QuickStart上的快速入门:

 // ref arguments var instance = new Bar(); // Only matches if the ref argument to the invocation is the same instance mock.Setup(foo => foo.Submit(ref instance)).Returns(true); 

不幸的是,如果没有Moq的直接支持,我不确定这是否可行。 问题是Lambda表达式不支持ref或out。

“lambda表达式不能直接从封闭方法中捕获ref或out参数。”

http://msdn.microsoft.com/en-us/library/bb397687.aspx

我甚至无法得到像你这样的例子来工作。 添加ref到设置无法编译。

您可以查看Moq讨论了解更多 http://groups.google.com/group/moqdisc

祝好运。

我遇到过类似的问题。 我通过使用最新的Moq获得解决方案并传递值

var instance = new Bar(); Mock.Setup(foo => foo.Submit(ref instance))。返回(true);

早些时候,我使用相同的方法,但我没有得到真正的回报。

在实际的函数实例内部被创建并覆盖从unit testing类传递的实例导致了问题。 我删除了实际类中的实例创建,然后它工作了。

希望它会对你有所帮助。

谢谢