asp.net-mvc – Moq的意外验证行为
|
Moq让我对我的最新项目感到有点疯狂.我最近升级到版本4.0.10827,我注意到在我看来是一个新的行为. 基本上,当我在我正在测试的代码中调用我的模拟函数(在本例中为MakeCall)时,我传入了一个对象(TestClass).我正在测试的代码在调用MakeCall之前和之后对TestClass对象进行了更改.代码完成后,我会调用Moq的Verify函数.我的期望是,Moq将记录我传入MakeCall的完整对象,可能是通过深度克隆等机制.通过这种方式,我将能够验证MakeCall是否被我希望调用的确切对象调用.不幸的是,这不是我所看到的. 我试图在下面的代码中说明这一点(希望在此过程中澄清一点). >我首先创建一个新的TestClass对象.它的Var属性设置为“1”. 对我来说,似乎很清楚Moq只保留对原始TestClass对象的引用,允许我改变其值而不受惩罚,对我的测试结果产生负面影响. 关于测试代码的一些注意事项. IMyMockedInterface是我嘲笑的界面. TestClass是我传递给MakeCall方法的类,因此用于演示我遇到的问题.最后,When_Testing是包含测试代码的实际测试类.它使用Machine.Specifications框架,这就是为什么有一些奇怪的项目(‘因为’,’它应该…’).这些只是框架调用以执行测试的委托.如果需要,应该很容易删除它们并将包含的代码放入标准函数中.我把它保留为这种格式,因为它允许所有Validate调用完成(与’Arrange,Act Assert’范例相比).只是为了澄清,下面的代码不是我遇到问题的实际代码.它只是为了说明问题,因为我在多个地方看到了同样的行为. using Machine.Specifications;
// Moq has a conflict with MSpec as they both have an 'It' object.
using moq = Moq;
public interface IMyMockedInterface
{
int MakeCall(TestClass obj);
}
public class TestClass
{
public string Var { get; set; }
// Must override Equals so Moq treats two objects with the
// same value as equal (instead of comparing references).
public override bool Equals(object obj)
{
if ((obj != null) && (obj.GetType() != this.GetType()))
return false;
TestClass t = obj as TestClass;
if (t.Var != this.Var)
return false;
return true;
}
public override int GetHashCode()
{
int hash = 41;
int factor = 23;
hash = (hash ^ factor) * Var.GetHashCode();
return hash;
}
public override string ToString()
{
return MvcTemplateApp.Utilities.ClassEnhancementUtilities.ObjectToString(this);
}
}
[Subject(typeof(object))]
public class When_Testing
{
// TestClass is set up to contain a value of 'one'
protected static TestClass t = new TestClass() { Var = "one" };
protected static moq.Mock<IMyMockedInterface> mockedObject = new moq.Mock<IMyMockedInterface>();
Because of = () =>
{
mockedObject.Object.MakeCall(t);
};
// Test One
// Expected: Moq should verify that MakeCall was called with a TestClass with a value of 'one'.
// Actual: Moq does verify that MakeCall was called with a TestClass with a value of 'one'.
// Result: This is correct.
It should_verify_that_make_call_was_called_with_a_value_of_one = () =>
mockedObject.Verify(o => o.MakeCall(new TestClass() { Var = "one" }),moq.Times.Once());
// Update the original object to contain a new value.
It should_update_the_test_class_value_to_two = () =>
t.Var = "two";
// Test Two
// Expected: Moq should verify that MakeCall was called with a TestClass with a value of 'one'.
// Actual: The Verify call fails,claiming that MakeCall was never called with a TestClass instance with a value of 'one'.
// Result: This is incorrect.
It should_verify_that_make_call_was_called_with_a_class_containing_a_value_of_one = () =>
mockedObject.Verify(o => o.MakeCall(new TestClass() { Var = "one" }),moq.Times.Once());
// Test Three
// Expected: Moq should fail to verify that MakeCall was called with a TestClass with a value of 'two'.
// Actual: Moq actually does verify that MakeCall was called with a TestClass with a value of 'two'.
// Result: This is incorrect.
It should_fail_to_verify_that_make_call_was_called_with_a_class_containing_a_value_of_two = () =>
mockedObject.Verify(o => o.MakeCall(new TestClass() { Var = "two" }),moq.Times.Once());
}
我有几个问题: 这是预期的行为吗? 我谦卑地感谢你提供任何帮助. 编辑: // This is the MVC Controller Action that I am testing. Note that it
// makes changes to the 'searchProjects' object before and after
// calling 'repository.SearchProjects'.
[HttpGet]
public ActionResult List(int? page,[Bind(Include = "Page,SearchType,SearchText,BeginDate,EndDate")]
SearchProjects searchProjects)
{
int itemCount;
searchProjects.ItemsPerPage = profile.ItemsPerPage;
searchProjects.Projects = repository.SearchProjects(searchProjects,profile.UserKey,out itemCount);
searchProjects.TotalItems = itemCount;
return View(searchProjects);
}
// This is my test class for the controller's List action. The controller
// is instantiated in an Establish delegate in the 'with_project_controller'
// class,along with the SearchProjectsRequest,SearchProjectsRepositoryGet,// and SearchProjectsResultGet objects which are defined below.
[Subject(typeof(ProjectController))]
public class When_the_project_list_method_is_called_via_a_get_request
: with_project_controller
{
protected static int itemCount;
protected static ViewResult result;
Because of = () =>
result = controller.List(s.Page,s.SearchProjectsRequest) as ViewResult;
// This test fails,as it is expecting the 'SearchProjects' object
// to contain:
// Page,EndDate and ItemsPerPage
It should_call_the_search_projects_repository_method = () =>
s.Repository.Verify(r => r.SearchProjects(s.SearchProjectsRepositoryGet,s.UserKey,out itemCount),moq.Times.Once());
// This test succeeds,EndDate,ItemsPerPage,// Projects and TotalItems
It should_call_the_search_projects_repository_method = () =>
s.Repository.Verify(r => r.SearchProjects(s.SearchProjectsResultGet,moq.Times.Once());
It should_return_the_correct_view_name = () =>
result.ViewName.ShouldBeEmpty();
It should_return_the_correct_view_model = () =>
result.Model.ShouldEqual(s.SearchProjectsResultGet);
}
/////////////////////////////////////////////////////
// Here are the values of the three test objects
/////////////////////////////////////////////////////
// This is the object that is returned by the client.
SearchProjects SearchProjectsRequest = new SearchProjects()
{
SearchType = SearchTypes.ProjectName,SearchText = GetProjectRequest().Name,Page = Page
};
// This is the object I am expecting the repository method to be called with.
SearchProjects SearchProjectsRepositoryGet = new SearchProjects()
{
SearchType = SearchTypes.ProjectName,Page = Page,ItemsPerPage = ItemsPerPage
};
// This is the complete object I expect to be returned to the view.
SearchProjects SearchProjectsResultGet = new SearchProjects()
{
SearchType = SearchTypes.ProjectName,ItemsPerPage = ItemsPerPage,Projects = new List<Project>() { GetProjectRequest() },TotalItems = TotalItems
};
解决方法最后,您的问题是模拟框架是否应该在与模拟交互时使用您所使用的参数的快照,以便它可以准确地记录系统在交互点处的状态,而不是参数可能位于的状态.验证点.从逻辑的角度来看,我认为这是一个合理的期望.您正在执行值为Y的操作X.如果您询问模拟“我是否执行了值为Y的操作X”,则无论系统的当前状态如何,您都希望它为“是”. 总结您遇到的问题: (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net-core – 如何在ASP.NET 5 MVC中访问缓存?
- asp.net-mvc-3 – Autofac等同于Ninject的WhenInjectedInto
- asp.net-mvc – 用于Firefox的Windows认证网站提示,但不适用
- asp.net – 如何保护我的AngularJS和Web Api应用程序
- ASP.NET page_init事件?
- asp.net – 链接按钮属性在新选项卡中打开?
- asp.net-mvc – Windows Azure上的ASP.NET MVC是生产环境的
- asp.net – 停止从域(也称为“无Cookie域”)设置Cookie以增
- 如何在ASP.NET中动态生成列表项到无序列表?
- asp.net – 跟踪像素或javascript包括?
- asp.net-mvc – ASP.Net T4MVC文件未自行更新
- asp.net验证文本框 – 至少有一个文本框必须包含
- asp.net – Ninject程序集与引用的程序集不匹配
- asp.net-mvc – 使用Windows身份验证与活动目录组
- asp.net-core – 加密ASP.Net Core中的连接字符串
- ASP.NET Page_Init被解雇了两次!
- asp.net-mvc – MVC HandleError过滤器没有捕获异
- asp.net-mvc – ASP MVC Razor视图扩展方法,如何
- iis – w3wp.exe占用内存
- asp.net – Web.config自定义错误模式冲突
