- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
TryUpdateModelAsync 是抽象类 PageModel 的一个内部保护方法,在我看来,这使得它不可模拟。是否有任何方法可以对涉及此方法的任何操作进行单元测试?
我在网上看到这个解决方案: asp.net core mvc controller unit testing when using TryUpdateModel .
但是,它只适用于 ASP.NET Core MVC Web App,因为 TryUpdateModelAsync 是一个公共(public)方法,所以我们可以添加一个适配器来包装这个方法,让我们的适配器调用实际的方法。在 Razor 页面中,无法从外部访问此 TryUpdateModelAsync。
我现在遇到的问题是当我对 OnPostAsync 方法进行单元测试时,TryUpdateModelAsync
总是抛出异常。我永远无法通过那条线来检查它之后的代码逻辑。
所以这是我要进行单元测试的操作:
public class CreateModel : PageModel
{
//elided
[BindProperty]
public Post Post { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
if (await TryUpdateModelAsync<Post>(Post, "Post", p => p.Title, p => p.SubTitle, p => p.Author, p => p.Content, p => p.CategoryID)){
//do stuff
return RedirectToPage("./Index");
}
//do stuff
return Page();
}
这是我为它编写的单元测试:
[Test]
public async Task InvokeOnPostAsyncWithInvalidModelState_ShouldReturnPageResultType(){
//Arrange
InitPostModelProperties();
var createModel = new CreateModel(){
PageContext = _pageContext,
TempData = _tempData,
Url = _urlHelper
};
//do arrangement
//Act
var result = await createModel.OnPostAsync();
//Assert
}
更新:
下面是我为这个测试所做的完整初始化过程:
public void InitPostModelProperties(){
_httpContext = new DefaultHttpContext(){
//RequestServices = services.BuildServiceProvider()
};
_modelStateDictionary = new ModelStateDictionary();
_modelMetaDataProvider = new EmptyModelMetadataProvider();
_actionContext = new ActionContext(_httpContext, new RouteData(), new PageActionDescriptor(), _modelStateDictionary);
_viewData = new ViewDataDictionary(_modelMetaDataProvider, _modelStateDictionary);
_tempData = new TempDataDictionary(_httpContext, Mock.Of<ITempDataProvider>());
_pageContext = new PageContext(_actionContext){
ViewData = _viewData
};
_urlHelper = new UrlHelper(_actionContext);
}
然后我收到以下异常消息:
Error Message:
System.ArgumentNullException : Value cannot be null.
Parameter name: metadataProvider
Stack Trace:
at Microsoft.AspNetCore.Mvc.ModelBinding.Internal.ModelBindingHelper.TryUpdateModelAsync(Object model, Type modelType, String prefix, ActionContext actionContext, IModelMetadataProvider metadataProvider, IModelBinderFactory modelBinderFactory, IValueProvider valueProvider, IObjectModelValidator objectModelValidator, Func`2 propertyFilter)
at Microsoft.AspNetCore.Mvc.RazorPages.PageModel.TryUpdateModelAsync[TModel](TModel model, String name, Expression`1[] includeExpressions)
然后我将初始化更改为以下内容:
public void InitPostModelProperties(){
var services = new ServiceCollection();
services.AddTransient<IModelMetadataProvider, ModelMetadataProvider>();
_httpContext = new DefaultHttpContext(){
RequestServices = services.BuildServiceProvider()
};
_modelStateDictionary = new ModelStateDictionary();
_modelMetaDataProvider = new EmptyModelMetadataProvider();
_actionContext = new ActionContext(_httpContext, new RouteData(), new PageActionDescriptor(), _modelStateDictionary);
_viewData = new ViewDataDictionary(_modelMetaDataProvider, _modelStateDictionary);
_tempData = new TempDataDictionary(_httpContext, Mock.Of<ITempDataProvider>());
_pageContext = new PageContext(_actionContext){
ViewData = _viewData
};
_urlHelper = new UrlHelper(_actionContext);
}
然后我得到了新的异常信息:
Outcome: Failed
Error Message:
System.InvalidOperationException : No service for type 'Microsoft.AspNetCore.Mvc.ModelBinding.IModelMetadataProvider' has been registered.
Stack Trace:
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Mvc.RazorPages.PageModel.get_MetadataProvider()
at Microsoft.AspNetCore.Mvc.RazorPages.PageModel.TryUpdateModelAsync[TModel](TModel model, String name, Expression`1[] includeExpressions)
我按照异常消息添加了这些行:
services.AddSingleton<IModelMetadataProvider, EmptyModelMetadataProvider>();
收到新的异常消息:
Outcome: Failed
Error Message:
System.InvalidOperationException : No service for type 'Microsoft.AspNetCore.Mvc.ModelBinding.IModelBinderFactory' has been registered.
Stack Trace:
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Mvc.RazorPages.PageModel.get_ModelBinderFactory()
at Microsoft.AspNetCore.Mvc.RazorPages.PageModel.TryUpdateModelAsync[TModel](TModel model, String name, Expression`1[] includeExpressions)
我一直在添加新行:
services.AddSingleton<IModelBinderFactory,ModelBinderFactory>();
才发现服务无法实例化,因为ModelBinderFactory类是抽象类
我被困在这里了。
更新
整个测试代码如下:
源代码:
public class BaseTests
{
private HugoBlogContext _context;
public HugoBlogContext Context => _context;
public List<Category> CatList;
public List<Post> PostList;
public List<Tag> TagList;
public List<PostTag> PostTagList;
public BaseTests(){}
public class PageModelBaseTests: BaseTests
{
protected ICategoryRepository _categoryRepository;
protected IPostRepository _postRepository;
protected IPostTagRepository _postTagRepository;
protected ITagRepository _tagRepository;
protected ISelectTagService _selectTagService;
protected IDropdownCategoryService _dropdownCategoryService;
protected HttpContext _httpContext;
protected ModelStateDictionary _modelStateDictionary;
protected ActionContext _actionContext;
protected ModelMetadataProvider _modelMetaDataProvider;
protected ViewDataDictionary _viewData;
protected TempDataDictionary _tempData;
protected PageContext _pageContext;
protected UrlHelper _urlHelper;
[SetUp]
public void Init(){
_categoryRepository = new CategoryRepository(Context);
_postRepository = new PostRepository(Context);
_postTagRepository = new PostTagRepository(Context);
_tagRepository = new TagRepository(Context);
_selectTagService = new SelectTagService(_tagRepository, _postRepository, _postTagRepository);
_dropdownCategoryService = new DropdownCategoryService(_categoryRepository);
}
public void InitPostModelProperties(){
var services = new ServiceCollection();
services.AddSingleton<IModelMetadataProvider, EmptyModelMetadataProvider>();
services.AddSingleton<IModelBinderFactory,ModelBinderFactory>();
_httpContext = new DefaultHttpContext(){
RequestServices = services.BuildServiceProvider()
};
_modelStateDictionary = new ModelStateDictionary();
_modelMetaDataProvider = new EmptyModelMetadataProvider();
_actionContext = new ActionContext(_httpContext, new RouteData(), new PageActionDescriptor(), _modelStateDictionary);
_viewData = new ViewDataDictionary(_modelMetaDataProvider, _modelStateDictionary);
_tempData = new TempDataDictionary(_httpContext, Mock.Of<ITempDataProvider>());
_pageContext = new PageContext(_actionContext){
ViewData = _viewData
};
_urlHelper = new UrlHelper(_actionContext);
}
[TestFixture]
public class CreateModelTests: PageModelBaseTests
{
[Test]
public async Task InvokeOnPostAsyncWithValidModelState_ShouldReturnRedirectPageResultTypeAndCategoryShouldBeUpdated(){
//Arrange
InitPostModelProperties();
var createModel = new CreateModel(_selectTagService, _dropdownCategoryService ,_postRepository){
PageContext = _pageContext,
TempData = _tempData,
Url = _urlHelper,
};
createModel.Post = new Post{
Title = "Create",
SubTitle = "Create",
Content = "Create",
Author = "Create",
CategoryID = CatList.Count + 1,
};
var selectedTags = new string[3]{"4","5","6"};
//Act
var result = await createModel.OnPostAsync(selectedTags);
//Assert
result.Should().BeOfType<RedirectToPageResult>();
Context.Posts.Where(c => c.CategoryID == (CatList.Count + 1)).Should().NotBeNull();
}
}
更新模拟后,我收到以下异常消息:
Outcome: Failed
Error Message:
System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
at Microsoft.AspNetCore.Mvc.ModelBinding.Internal.ModelBindingHelper.TryUpdateModelAsync(Object model, Type modelType, String prefix, ActionContext actionContext, IModelMetadataProvider metadataProvider, IModelBinderFactory modelBinderFactory, IValueProvider valueProvider, IObjectModelValidator objectModelValidator, Func`2 propertyFilter)
at Microsoft.AspNetCore.Mvc.RazorPages.PageModel.TryUpdateModelAsync[TModel](TModel model, String name, Expression`1[] includeExpressions)
仅供引用:我还 mock 了IObjectValidator
通过使用 services.AddSingleton<IObjectValidator>(Mock.Of<IObjectValidator>())
最佳答案
我不确定测试 TryValidateModel
或 TryUpdateModelAsync
是我们的责任;可以安全地假设框架方法是正确的,对吧。
另一个论点是您正在测试您的实现而不是其他人的。
无论如何,如果你想忽略这些方法,你可以在你的测试方法中尝试这个(我正在使用 Moq 作为我的模拟框架)完全忽略这些方法并且实际上假设它们是正确的:
var objectModelValidatorMock = new Mock<IObjectModelValidator>();
objectModelValidatorMock
.Setup(o => o.Validate(
It.IsAny<ActionContext>(),
It.IsAny<ValidationStateDictionary>(),
It.IsAny<string>(),
It.IsAny<object>()));
var sut = new NewController
{
ObjectValidator = objectModelValidatorMock.Object
};
关于c# - 如何使用 ASP.NET CORE Razor Page Web App 中涉及的 TryUpdateModelAsync 对方法进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57641311/
我有一个 TryUpdateModelAsync 调用,一旦失败,只会返回 false。目前还不清楚它失败的原因。我怎样才能获得更多信息? if (await TryUpdateModelAsync(
我有一个 TryUpdateModelAsync 调用,一旦失败,只会返回 false。目前还不清楚它失败的原因。我怎样才能获得更多信息? if (await TryUpdateModelAsync(
我用这样的模型绑定(bind)更新我的数据库: var adminUpdate = await _context.Admins.FindAsync(Id); if (!String.IsNullOrE
我有以下代码: if (await TryUpdateModelAsync( hostToUpdate, "Host",
所以我正在这样做 microsoft tutorial在带有 EF 6 的 ASP.NET Core 上,它刚刚通过编辑 Controller 更新了一个模型。 这段代码让我非常困惑,我想(也许希望)
假设我有一个包含以下模型结构的表单: TestRecord.cs class TestRecord { public string Id { get; set; } public st
TryUpdateModelAsync 是抽象类 PageModel 的一个内部保护方法,在我看来,这使得它不可模拟。是否有任何方法可以对涉及此方法的任何操作进行单元测试? 我在网上看到这个解决方案:
我是一名优秀的程序员,十分优秀!