如何对返回匿名对象的ASP.NET Core MVC控制器进行单元测试?

行话

我在测试返回匿名对象的ASP.NET Core MVC控制器时遇到了麻烦。单元测试是在单独的项目中设置的,并直接从主项目中调用控制器方法。

控制器方法返回,IActionResult但通常这些是OkObjectResultBadRequestObjectResult对象,它们使用适当的HTTP状态代码转换为JSON响应。匿名对象是作为对象的构造函数参数传递的ObjectResult,正是我试图针对这些对象进行断言(可通过访问ObjectResult.Value)。

我发现了这个问题(如何在asp.net 5中访问内部函数),该问题的回答是使用动态和添加

[assembly: InternalsVisibleTo("Namespace")]

到AssemblyInfo.cs,以允许测试项目访问匿名对象的内部对象属性。但是,最新版本的ASP.NET Core MVC没有AssemblyInfo.cs,并且按照链接问题的答案中的建议添加一个也不起作用。

现在是否有其他位置可以添加,InternalsVisibleTo或者我错过了什么?

恩科西

从最初的想法这个答案有一个更通用的方法。使用自定义DynamicObject包装作为通过反射检查值的包装器,无需添加InternalsVisibleTo

public class DynamicObjectResultValue : DynamicObject, IEquatable<DynamicObjectResultValue> {
    private readonly object value;

    public DynamicObjectResultValue(object value) {
        this.value = value;
    }

    #region Operators
    public static bool operator ==(DynamicObjectResultValue a, DynamicObjectResultValue b) {
        // If both are null, or both are same instance, return true.
        if (System.Object.ReferenceEquals(a, b)) {
            return true;
        }
        // If one is null, but not both, return false.
        if (ReferenceEquals((object)a, null) || ReferenceEquals((object)b, null)) {
            return false;
        }
        // Return true if the fields match:
        return a.value == b.value;
    }

    public static bool operator !=(DynamicObjectResultValue a, DynamicObjectResultValue b) {
        return !(a == b);
    }
    #endregion

    public override IEnumerable<string> GetDynamicMemberNames() {
        return value.GetType().GetProperties().Select(p => p.Name);
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result) {
        //initialize value
        result = null;
        //Search possible matches and get its value
        var property = value.GetType().GetProperty(binder.Name);
        if (property != null) {
            // If the property is found, 
            // set the value parameter and return true. 
            var propertyValue = property.GetValue(value, null);
            result = propertyValue;
            return true;
        }
        // Otherwise, return false. 
        return false;
    }

    public override bool Equals(object obj) {
        if (obj is DynamicObjectResultValue)
            return Equals(obj as DynamicObjectResultValue);
        // If parameter is null return false.
        if (ReferenceEquals(obj, null)) return false;
        // Return true if the fields match:
        return this.value == obj;
    }

    public bool Equals(DynamicObjectResultValue other) {
        // If parameter is null return false.
        if (ReferenceEquals(other, null)) return false;
        // Return true if the fields match:
        return this.value == other.value;
    }

    public override int GetHashCode() {
        return ToString().GetHashCode();
    }

    public override string ToString() {
        return string.Format("{0}", value);
    }
}

假设以下控制器

public class FooController : Controller {

    public IActionResult GetAnonymousObject() {

        var jsonResult = new {
            id = 1,
            name = "Foo",
            type = "Bar"
        };

        return Ok(jsonResult);
    }

    public IActionResult GetAnonymousCollection() {

        var jsonResult = Enumerable.Range(1, 20).Select(x => new {
            id = x,
            name = "Foo" + x,
            type = "Bar" + x
        }).ToList();

        return Ok(jsonResult);
    }
}

测试可能看起来像

[TestMethod]
public void TestDynamicResults() {
    //Arrange
    var controller = new FooController();

    //Act
    var result = controller.GetAnonymousObject() as OkObjectResult;

    //Assert
    dynamic obj = new DynamicObjectResultValue(result.Value);

    Assert.IsNotNull(obj);
    Assert.AreEqual(1, obj.id);
    Assert.AreEqual("Foo", obj.name);
    Assert.AreEqual(3, obj.name.Length);
    Assert.AreEqual("Bar", obj.type);
}

[TestMethod]
public void TestDynamicCollection() {
    //Arrange
    var controller = new FooController();

    //Act
    var result = controller.GetAnonymousCollection() as OkObjectResult;

    //Assert
    Assert.IsNotNull(result, "No ActionResult returned from action method.");
    dynamic jsonCollection = result.Value;
    foreach (dynamic value in jsonCollection) {
        dynamic json = new DynamicObjectResultValue(value);

        Assert.IsNotNull(json.id,
            "JSON record does not contain \"id\" required property.");
        Assert.IsNotNull(json.name,
            "JSON record does not contain \"name\" required property.");
        Assert.IsNotNull(json.type,
            "JSON record does not contain \"type\" required property.");
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在ASP.NET Core 1.1中对使用HttpContext的MVC控制器进行单元测试

单元测试 ASP.NET Core 3.1 MVC 控制器 - 值不能为空。(参数'提供者')

ASP.NET MVC5:对具有会话的控制器进行单元测试

Asp.net Core Identity单元测试控制器操作

ASP.Net Core单元测试异步控制器

如何使用ASP.NET 5(MVC 6)中的Response属性对控制器动作进行单元测试?

ASP.NET Core 3.1 中 API 控制器的单元测试返回错误的状态代码

测试控制器问题响应时,ASP.NET Core单元测试抛出Null异常

使用JWT声明对.NET Core Web API控制器进行单元测试

使用 xunit 和 moq 进行 net core api 控制器单元测试

ASP.NET 5-MVC 6-对使用Url.Action的控制器进行单元测试

单元测试-控制器未从ASP.NET Core Web API项目中的模拟IConfiguration中获取值

如何单元测试Core MVC控制器动作是否调用ControllerBase.Problem()

带有构造函数注入的单元测试ASP.NET MVC控制器

ASP.NET MVC:使用UrlHelper的单元测试控制器

C#ASP.NET MVC控制器单元测试

如何在ASP.NET Core MVC中对RazorViewEngineOptions进行单元测试?

ASP.net Core MVC测试/使控制器返回字符串?

单元测试.NET Core 3 Web API控制器

具有异步Task <ActionResult>的单元测试ASP.NET MVC 5控制器

在ASP.NET Core中对自定义密码验证器进行单元测试

.NET Core如何进行单元测试服务?

如何在返回对象的ASP.NET Core WebAPI控制器中引发异常?

模拟HttpContext来对.NET核心MVC控制器进行单元测试?

如何对返回模型的控制器进行单元测试?

Spring MVC:如何通过返回String的控制器方法对模型的属性进行单元测试?

在.Net Core中测试控制器始终返回false?

如何对ASP.NET Core Web应用程序(.Net Framework)进行单元测试?

ASP.Net Web API控制器单元测试失败