繁体   English   中英

Asp.net 内核 session 单元测试

[英]Asp.net core session unit test

我在单元测试 asp.net 核心 mvc controller 时遇到问题,问题是在我的 controller 中:我使用会话:

[HttpPost]
public IActionResult OpretLobby(LobbyViewModel lobby)
{
    try
    {
        //find brugeren der har lavet lobby
        var currentUser = HttpContext.Session.GetObjectFromJson<User>("user");
        //save as a lobby
        ILobby nyLobby = new Lobby(currentUser.Username)
        {
            Id = lobby.Id
        };
        SessionExtension.SetObjectAsJson(HttpContext.Session, lobby.Id, nyLobby);
        //add to the list
        _lobbyList.Add(nyLobby);
        return RedirectToAction("Lobby","Lobby",lobby);
    }

这一切都在服务器上运行得很好,这里没有错。 但是当涉及到对整个事情进行单元测试的需求时,它就不再那么完美了。

基本上问题是,我无法从测试中访问我的 session .. 我已经尝试了很多方法来创建模拟,但大多数解决方案都适用于 .net 框架,而不是 Z2D509452FECD106202 出于某种原因! 请帮助我痛苦!

笔记:

我使用了一个虚拟版本的测试来隔离这个问题:

[Test]
public void TestIsWorking()
{
    SessionExtension.SetObjectAsJson(uut.HttpContext.Session, "user", _savedUser);
    //ViewResult result = uut.OpretLobby(lobbyViewModel) as ViewResult;

    //Assert.AreEqual("OpretLobby", result.ViewName);
    Assert.AreEqual(1,1);
}

在这里尝试为用户设置 session 时也会出错:/

看来GetObjectFromJson是一种扩展方法。 如果是这样,我们就不能轻松地模拟 static 方法。

我通常为这种场景创建一个抽象。 然后将其注册到 DI 容器中,并将依赖注入到 controller。

启动.cs

public class Startup
{
    ...
    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddScoped<IUserSession, UserSession>();
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        ...
    }
    ...
}

抽象

public class User
{
    public string Username { get; set; }
}

public interface IUserSession
{
    User User { get; }
}

public class UserSession : IUserSession
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public UserSession(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public User User => _httpContextAccessor.HttpContext.Session.GetObjectFromJson<User>("user");
}

public static class SessionExtensions
{
    public static User GetObjectFromJson<User>(
        this ISession sesson, string json) where User : new()
    {
        return new User(); // Dummy extension method just to test OP's code
    }
}

Controller

public class HomeController : Controller
{
    private readonly IUserSession _userSession;

    public HomeController(IUserSession userSession)
    {
        _userSession = userSession;
    }

    public IActionResult OpretLobby()
    {
        var currentUser = _userSession.User;
        return View(currentUser);
    }
}

}

单元测试

using AspNetCore.Controllers;
using Microsoft.AspNetCore.Mvc;
using Moq;
using Xunit;

namespace XUnitTestProject1
{
    public class HomeControllerTests
    {
        private readonly User _user;

        public HomeControllerTests()
        {
            _user = new User {Username = "johndoe"};
        }

        [Fact]
        public void OpretLobby_Test()
        {
            // Arrange
            var mockUserSession = new Mock<IUserSession>();
            mockUserSession.Setup(x => x.User).Returns(_user);
            var sut = new HomeController(mockUserSession.Object);

            // Act
            var result = sut.OpretLobby();

            // Assert
            var viewResult = Assert.IsType<ViewResult>(result);
            var user = Assert.IsType<User>(viewResult.Model);
            Assert.Equal(_user.Username, user.Username);
        }
    }
}

@nicholas-ladefoged

当您需要从 session 获取一些内容时,我宁愿建议您使用集成测试

asp.net 内核有一个很棒的TestHost nuget package,它可以帮助您使用集成方式验证逻辑进行测试。

尝试添加下面的代码片段

TestServer server = new TestServer(new WebHostBuilder()
            .UseStartup<Startup>()
            .ConfigureTestServices(services =>
            {
                services.AddHttpContextAccessor();
            }));
var client = server.CreateClient();

var response = await client.GetAsync(""); // I'm using GetAsync just for sample

干得好! 您将拥有一个可以测试的真正的 session

顺便说一句,Moq 库无法模拟 static 方法,因此存在很多问题。 我认为在您的情况下使用集成测试会更容易

赢解决了。 如果有人想知道,这是最终的测试代码。

// Arrange
var mockUserSession = new Mock<IUserSession>();
mockUserSession.Setup(x => x.User).Returns(_savedUser);
var sut = new LobbyController(FakeSwagCommunication,mockUserSession.Object);

// Act
var result = sut.OpretLobby(_lobbyViewModel);

// Assert
Assert.IsInstanceOf<RedirectToActionResult>(result);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM