ASP.NET核心会话单元测试



i hava在单位测试ASP.NET核心MVC控制器中有一个问题!问题是在我的控制器中,我使用会话:

[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);
    }

这一切都很好地在线上运行良好,这里没有错。但是,当涉及单位测试这整个过程的需求时,它不再那么完美了。

基本上的问题是,我无法从测试中访问我的会话。我尝试以多种方式创建模拟,而不是什么,但是大多数解决方案都适用于.NET框架,而不是用于.NET由于某种原因,核心!请帮助我痛苦!

注意:

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

[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);
}

在这里也错了,试图为用户设置会话:/

看来GetObjectFromJson是一种扩展方法。如果是这样,我们无法模拟静态方法

我通常为这种情况创建一个抽象。然后将其注册在DI容器中,然后将依赖项注入控制器。

startup.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
    }
}

控制器

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 Core具有很棒的TestHost Nuget软件包,可以通过集成方法来帮助您验证逻辑。

尝试添加下面的代码段

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

你去!您将有一个真实的会话,您可以测试

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

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

// 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);

最新更新