gpt4 book ai didi

c# - 对方法参数的 BindAttribute 进行单元测试

转载 作者:太空狗 更新时间:2023-10-29 20:30:24 25 4
gpt4 key购买 nike

我希望编写单元测试来验证我的 Controller ,同时确保正确设置绑定(bind)属性。使用以下方法结构,如何确保仅通过单元测试的有效字段?

public ActionResult AddItem([Bind(Include = "ID, Name, Foo, Bar")] ItemViewModel itemData)
{
if (ModelState.IsValid)
{
// Save and redirect
}

// Set Error Messages
// Rebuild object drop downs, etc.
itemData.AllowedFooValues = new List<Foo>();
return View(itemData);
}

更广泛的解释:我们的许多模型都有我们不想来回发送的允许值列表,因此我们在 (ModelState.IsValid == false) 时重建它们。为了确保所有这些工作正常,我们希望进行单元测试以断言列表已重建,但在调用方法之前不清除列表,测试无效。

我们正在使用这个 SO answer 中的辅助方法以确保模型得到验证,然后我们的单元测试就是这样的。

    public void MyTest()
{
MyController controller = new MyController();

ActionResult result = controller.AddItem();
Assert.IsNotNull(result);
ViewResult viewResult = result as ViewResult;
Assert.IsNotNull(viewResult);
ItemViewModel itemData = viewResult.Model as ItemViewModel;
Assert.IsNotNull(recipe);
// Validate model, will fail due to null name
controller.ValidateViewModel<ItemViewModel, MyController>(itemData);

// Call controller action
result = controller.AddItem(itemData);
Assert.IsNotNull(result);
viewResult = result as ViewResult;
Assert.IsNotNull(viewResult);
itemData = viewResult.Model as ItemViewModel;
// Ensure list was rebuilt
Assert.IsNotNull(itemData.AllowedFooValues);
}

非常感谢任何指向正确方向的帮助或指示。

最佳答案

我可能误解了你的意思,但听起来你想要一些东西来确保你在测试中创建的模型在传递给你的 Controller 之前被过滤,以模拟 MVC 绑定(bind)并防止您不小心编写了一个测试,该测试将信息传递给被测 Controller ,而该信息永远不会被框架实际填充。

考虑到这一点,我假设您只真正对具有 Include 成员集的 Bind 属性感兴趣。在这种情况下你可以使用这样的东西:

public static void PreBindModel<TViewModel, TController>(this TController controller, 
TViewModel viewModel,
string operationName) {
foreach (var paramToAction in typeof(TController).GetMethod(operationName).GetParameters()) {
foreach (var bindAttribute in paramToAction.CustomAttributes.Where(x => x.AttributeType == typeof(BindAttribute))) {
string properties;
try {
properties = bindAttribute.NamedArguments.Where(x => x.MemberName == "Include").First().TypedValue.Value.ToString();
}
catch (InvalidOperationException) {
continue;
}
var propertyNames = properties.Split(',');

var propertiesToReset = typeof(TViewModel).GetProperties().Where(x => propertyNames.Contains(x.Name) == false);

foreach (var propertyToReset in propertiesToReset) {
propertyToReset.SetValue(viewModel, null);
}
}
}
}

在你像这样调用 Controller 操作之前,它会从你的单元测试中调用:

controllerToTest.PreBindModel(model, "SomeMethod");
var result = controllerToTest.SomeMethod(model);

本质上,它所做的是遍历传递给给定 Controller 方法的每个参数,寻找绑定(bind)属性。如果找到绑定(bind)属性,则获取 Include 列表,然后重置包含列表中未提及的 viewModel 的每个属性(基本上解除绑定(bind)) .

上面的代码可能需要一些调整,我没有做太多的 MVC 工作,所以我对属性和模型的使用做了一些假设。

上述代码的改进版本,使用 BindAttribute 本身进行过滤:

public static void PreBindModel<TViewModel, TController>(this TController controller, TViewModel viewModel, string operationName) {
foreach (var paramToAction in typeof(TController).GetMethod(operationName).GetParameters()) {
foreach (BindAttribute bindAttribute in paramToAction.GetCustomAttributes(true)) {//.Where(x => x.AttributeType == typeof(BindAttribute))) {
var propertiesToReset = typeof(TViewModel).GetProperties().Where(x => bindAttribute.IsPropertyAllowed(x.Name) == false);

foreach (var propertyToReset in propertiesToReset) {
propertyToReset.SetValue(viewModel, null);
}
}
}
}

关于c# - 对方法参数的 BindAttribute 进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30671033/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com