如何对返回匿名对象的 ASP.NET Core MVC 控制器进行单元测试? [英] How do you unit test ASP.NET Core MVC Controllers that return anonymous objects?

查看:37
本文介绍了如何对返回匿名对象的 ASP.NET Core MVC 控制器进行单元测试?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在对返回匿名对象的 ASP.NET Core MVC 控制器进行单元测试时遇到问题.单元测试设置在单独的项目中,直接从主项目调用控制器方法.

I'm having trouble unit testing ASP.NET Core MVC controllers that return anonymous objects. The unit testing is set up in a separate project and calls the controller methods from the main project directly.

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

The controller methods return IActionResult but typically these are OkObjectResult and BadRequestObjectResult objects that get translated into a JSON response with the appropriate HTTP status code. The anonymous objects are passed as the constructor parameters for the ObjectResult objects and it is these I'm trying to make assertions against (accessible via ObjectResult.Value).

我发现了这个问题(如何在asp.net 5) 的答案是使用动态和添加

I found this question (how can i access internals in asp.net 5) that has an answer that says to use dynamics and add

[assembly: InternalsVisibleTo("Namespace")]

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

to AssemblyInfo.cs to allow the test project access to the internal object properties of the anonymous objects. However, latest versions of ASP.NET Core MVC do not have AssemblyInfo.cs and adding one as suggested in the answers to the linked question does not work either.

现在有其他位置可以添加 InternalsVisibleTo 还是我遗漏了什么?

Is there now a different location to add the InternalsVisibleTo or am I missing something?

推荐答案

来自 this answer 的原始想法,更通用方法.使用自定义 DynamicObject 作为通过反射检查值的包装器,无需添加 InternalsVisibleTo

Original idea from this answer with a more generic approach. Using a custom DynamicObject as a wrapper for inspecting the value via reflection there was no need to add the 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.");
    }
}

这篇关于如何对返回匿名对象的 ASP.NET Core MVC 控制器进行单元测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆