Тестирование промежуточного программного обеспечения OWIN в ASP.NET WebApi 2: как установить файлы cookie? - PullRequest
0 голосов
/ 01 ноября 2018

Я пытаюсь протестировать компонент промежуточного программного обеспечения OWIN в приложении ASP.NET WebApi 2. Предполагается, что промежуточное программное обеспечение просматривает файлы cookie входящего запроса, изменяет некоторые элементы запроса до того, как оно будет передано следующему компоненту, и потенциально может также установить файлы cookie на выходе.

Меня сбивает с толку то, что свойство OwinRequest.Cookies имеет тип RequestCookieCollection, который, по-видимому, не позволяет изменять, а само свойство доступно только для чтения, что означает, что я не могу используйте конструктор RequestCookieCollection(IDictionary<string,string>), чтобы инициализировать коллекцию, в которой уже есть файлы cookie, и установить ее по запросу.

Я хочу сделать что-то вроде этого:

var context = new OwinContext();
// option 1:
context.Request.Cookies.Append("cookie-name", "cookie-value");
// option 2:
var cookies = new RequestCookieCollection(new Dictionary<string, string>{ { "cookie-name", "cookie-value" } });
context.Request.Cookies = cookies;

await myMiddleware.Invoke(context);

// Assert stuff about context.Response

но это не работает по вышеуказанным причинам.

Я надеялся, что мне не придется издеваться над IOwinContext до конца, потому что довольно удобно настроить его на хорошо функционирующие объекты Request и Response (мне нужно, среди прочего, взглянуть на Request.User.Identity.IsAuthenticated в моей реализации).

1 Ответ

0 голосов
/ 26 ноября 2018

Использование следующего в качестве предмета примера промежуточного программного обеспечения для модульного тестирования

using RequestDelegate = Func<IOwinContext, Task>;

class MyMiddleware {
    private readonly RequestDelegate next;

    public MyMiddleware(RequestDelegate next) {
        this.next = next;
    }

    public async Task Invoke(IOwinContext context) {
        //The middleware is supposed to look at the cookies of the incoming request, 
        var request = context.Request;
        var authenticated = request.User.Identity.IsAuthenticated;

        var cookies = request.Cookies;
        if (cookies["cookie-name"] != null) {
            // 1. check for existence of a cookie on the incoming request. 
            //if the cookie exists, use its value to set a header, 
            //so that the pipline after this component thinks the header was always present.
            request.Headers.Append("header-name", "header-value");
        }

        //2. call the next component.
        await next.Invoke(context);

        //3. on the way out, check for some conditions, and possibly set a cookie value.
        if (authenticated) {
            context.Response.Cookies.Append("cookie-name", "cookie-value");
        }
    }
}

и используя предоставленную информацию о желаемом поведении,

Было бы трудно провести модульное тестирование контроллера со всей сантехникой, необходимой для полного OwinContext.

Вы уже указали множество ограничений на доступ к некоторым членам.

Однако Овин предоставляет множество абстракций, которые позволили бы имитировать / заглушать / подделывать желаемое поведение для изолированного модульного теста.

Следующий пример основан на предмете, представленном выше, и использует инфраструктуру Moq mocking вместе с конкретными реализациями для правильной настройки и проведения изолированного модульного теста для промежуточного программного обеспечения объекта.

[TestClass]
public class OwinMiddlewareCookiesTest {
    [Test]
    public async Task MyMiddleware_Should_Set_RequestHeader_And_ResponseHeader() {
        //Arrange
        var cookieStore = new Dictionary<string, string> { { "cookie-name", "cookie-value" } };
        var cookies = new RequestCookieCollection(cookieStore);

        var request = Mock.Of<IOwinRequest>();
        var requestMock = Mock.Get(request);
        requestMock.Setup(_ => _.Cookies).Returns(cookies);
        requestMock.Setup(_ => _.User.Identity.IsAuthenticated).Returns(true);
        requestMock.Setup(_ => _.Headers.Append(It.IsAny<string>(), It.IsAny<string>()));

        var response = new OwinResponse();

        var context = Mock.Of<OwinContext>();
        var contextMock = Mock.Get(context);
        contextMock.CallBase = true;
        contextMock.Setup(_ => _.Request).Returns(request);
        contextMock.Setup(_ => _.Response).Returns(response);

        RequestDelegate next = _ => Task.FromResult((object)null);

        var myMiddleware = new MyMiddleware(next);

        //Act
        await myMiddleware.Invoke(context);

        //Assert
        requestMock.Verify(_ => _.Headers.Append("header-name", "header-value"));
        response.Headers.ContainsKey("Set-Cookie");
    }
}

Необходимо смоделировать только необходимые зависимости для завершения теста и проверки ожидаемого поведения.

И поскольку свойство Cookies реализации запроса не может быть переопределено, необходимо использовать абстракцию. Это, однако, обеспечило большую гибкость в издевательстве над желаемым поведением.

...