【问题标题】:c# Unit test mock class attributec#单元测试模拟类属性
【发布时间】:2025-12-22 06:05:08
【问题描述】:

在我的 MVC 项目中,我必须设置一个控制器类属性:

public class ResponsableAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);
        var controller = (BaseController)filterContext.Controller;
        if (!controller.EstResponsable)
        {
            filterContext.Result = controller.RedirectionForcee(Alertage.Information, ConstantesUi.Misc.MessageResponsable);
        }
    }
}

请耐心等待,代码是法语:

[Responsable]
public class ParamLivraisonController : BaseController

所以每个动作在执行之前都必须通过属性,这是预期的行为。 但我不知道如何对这个属性进行单元测试,将返回值设置为 false,以便 controller.RedirectionForcee(返回 RedirectToRouteResult)真正发挥作用。

如果我调用任何控制器方法:

[TestMethod]
public void ParamLivraisonController_GererLivraison_Get()
{
    ControleurAsynchrone.ObtenirLivraisons().Returns(ObtenirListeLivraison());
    var retour = _ctrl.GererLivraisons();
    Assert.IsNotNull(retour);
}

该属性未命中或测试。怎么能测试呢?我正在使用 nSubstitute 和 mvcFakes,但我不知道如何替换 ActionExecutingContext

【问题讨论】:

  • 隔离的单元测试的主题应该是属性。创建一个您控制的上下文并将其传递给OnActionExecuting 并断言所需的行为。否则,创建一个内存集成测试,它将在运行时端到端调用操作,其中还包括属性。
  • 有趣!你介意举个例子吗?
  • @KennethK。甚至不知道这是可能的。 :|

标签: c# unit-testing asp.net-mvc-5


【解决方案1】:

感谢@Kenneth K.,我找到了答案。 @Nkosi 提到测试应该在属性本身上也是正确的。

这里是:

    [TestMethod]
    public void ValiderAttribut_EstResponsable()
    {
        var attribut = new ResponsableAttribute(); // Instantiation of the attribute
        var controller = ObtenirController(); // Gets the controller via MvcFakes
        SecuriteHelper.VerifierResponsable().Returns(true); // Sets the desired return value
        var test = Substitute.For<ActionExecutingContext>(); // Substitute for ActionExecutingContext
        test.Controller = controller; // Sets the controller to the context

        attribut.OnActionExecuting(test); // Call the overrided method
        Assert.IsNull(test.Result); // Check if the redirection occured
    }

现在,为了验证测试是否正确,我还必须测试相反的结果:

    [TestMethod]
    public void ValiderAttribut_EstNonResponsable()
    {
        var attribut = new ResponsableAttribute();
        var controller = ObtenirController();
        SecuriteHelper.VerifierResponsable().Returns(false);
        var test = Substitute.For<ActionExecutingContext>();
        test.Controller = controller;

        attribut.OnActionExecuting(test);
        Assert.IsNotNull(test.Result);
        Assert.AreEqual(typeof(RedirectResult), test.Result.GetType());
    }

它奏效了。谢谢!

【讨论】:

  • 为了完成图片,我可能会使用反射添加测试以确保属性在ParamLivraisonController 类上;因此,如果有人不明白它为什么存在,则将其删除,测试将失败,测试名称将解释为什么该属性需要存在。