Как вы тестируете модульные контроллеры ASP.NET Core MVC, которые возвращают анонимные объекты?

c# unit-testing asp.net-core-mvc anonymous-types

4187 просмотра

1 ответ

166 Репутация автора

У меня проблемы с модульным тестированием контроллеров ASP.NET Core MVC, которые возвращают анонимные объекты. Модульное тестирование настроено в отдельном проекте и напрямую вызывает методы контроллера из основного проекта.

Методы контроллера возвращают , IActionResultно обычно это OkObjectResultи BadRequestObjectResultобъекты , которые переводятся в ответ JSON с соответствующим кодом состояния HTTP. Анонимные объекты передаются как параметры конструктора для ObjectResultобъектов, и именно на них я пытаюсь сделать утверждения (доступно через ObjectResult.Value).

Я нашел этот вопрос ( как я могу получить доступ к внутренним компонентам в asp.net 5 ), который имеет ответ, который говорит использовать динамику и добавить

[assembly: InternalsVisibleTo("Namespace")]

в AssemblyInfo.cs, чтобы разрешить тестовому проекту доступ к внутренним свойствам объекта анонимных объектов. Однако последние версии ASP.NET Core MVC не имеют AssemblyInfo.cs, и добавление одной из них, как предлагается в ответах на связанный вопрос, также не работает.

Есть ли другое место для добавления InternalsVisibleToили я что-то упустил?

Автор: Jargon Источник Размещён: 18.07.2016 02:51

Ответы (1)


21 плюса

142648 Репутация автора

Решение

Оригинальная идея из этого ответа с более общим подходом. При использовании обычая 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.");
    }
}
Автор: Nkosi Размещён: 18.07.2016 10:10
Вопросы из категории :
32x32