如何通过 Moq、ASP .NET MVC 进行模块测试

How make a module test by Moq, ASP .NET MVC

我有一个方法,它 return 是 return 视图执行 ajax 操作,我如何测试它以检查正确的数据 return 与否?

[HttpPost]
    public ActionResult ViewPlayers(string teamName)
    {
        if (teamName.Contains("Все игроки"))
        {
            return PartialView(playerRepository.Players.ToList());
        }
        else
        {

            if (teamName != string.Empty)// send team-logo image path
            {
                Team findingTeam = teamRepository.Teams.First(t => t.Name.Contains(teamName));
                ViewBag.TeamLogoPath = findingTeam.Path;
            }
            List<Player> allTeam = playerRepository.Players.Where(t => t.Team.Name.Contains(teamName)).ToList();

            return PartialView(allTeam);
        }
    }

当我在下拉列表中选择一个团队时,我会选择 string name 到 post 之后,

1) 如果 "Все игроки" 我与所有玩家一起 table

2) 否则我会在这支球队中找到球员。

如何签到测试return是全队球员还是部分球员?

您是否尝试过简单地调用该方法并检查响应? MVC 框架的优点在于您不需要 仅仅为了使用一个控制器就需要整个框架。堆栈中的其他组件将获取 ActionResult 并将其呈现为 HTML。

PartialView returns a PartialViewResult whose Model 属性 包含传递给 PartialView 的模型。

您应该能够编写单元测试来创建控制器、调用操作并检查结果的模型,例如:

[Test]
public void viewPlayers_Returns_One()
{
    var myController=new MyController(...);
    var resultView=(PartialViewResult)myController.ViewPlayers("SomeName");
    var players= (List<Player>)resultView.Model;

    Assert.That(players, Has.Exactly(1).Items);
}

嘲讽

现在棘手的部分是注入存储库。考虑到类似 LINQ 的语法,我假设 playerRepository 是通过构造函数注入的 EF 存储库或通过 Players 属性 公开 EF 实体的存储库对象。

模拟 EF 显示在多个 SO questions and the EF documentation.

EF Core 通过其 . EF Core isn't tied to the .NET runtime which means it can be used in Full framework applications too. Testing with InMemory in the docs contains a more detailed example. There's also an example that shows using SQLite for more advanced scenarios

使模拟变得容易得多

因为懒惰,我假设存储库是一个 class 实现了一个接口 :

public interface IPlayersRepository
{
    public IQueryable<Player> Players {get;}
}

创建一个模拟 class 很容易,它接受一个列表或数组或玩家并通过 Players 公开它:

class MockPlayers
{
    public IQueryable<Player> Players {get; private set;}

    public MockPlayers(Player[] players)
    {
        Players=players.AsQueryable();
    }
}

这很简单,甚至不需要模拟框架。之后,测试变为:

[Test]
public void viewPlayers_Returns_One()
{
    var players=new[]{new Player{Name="SomeName"},new Player{Name="Other Name"}};
    var mockRepo=new MockPlayers(players);
    var myController=new MyController(mockRepo);
    ...
}

Moq 对于更复杂的界面很有用。使用最小起订量,您可能会写:

var players = new[]{...};
var mockRepo=new Mock<IPlayersRepository>();
mockRepo.SetupGet(x => x.Players).Returns(players.AsQueryable());

EF 核心

如果您注入 EF Core 上下文,例如 PlayersContext,您可以将其配置为使用内存中提供程序:

//setup
var options = new DbContextOptionsBuilder<PlayersContext>()
    .UseInMemoryDatabase(databaseName: "Players Test")
    .Options;

using(var ctx = new PlayersContext(options))
{
    ctx.Players.Add(new Player{...});
    ctx.SaveChanges();
}

//Execute
using(var ctx = new PlayersContext(options))
{
    var myController=new MyController(ctx);
    ...
}

"Classic" EF

事情有点复杂,需要模拟 DbSet 及其一些方法。调整 documentation's query scenario 将如下所示:

//Setup 
...
var data = players.AsQueryable();

var mockSet = new Mock<DbSet<Player>>();
mockSet.As<IQueryable<Player>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Player>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Player>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Player>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

var mockContext = new Mock<PlayerContext>();
mockContext.Setup(c => c.Blogs).Returns(mockSet.Object);

//Execute
var myController=new MyController(mockContext.Object);
...

我有没有提到 EF Core 可以在完整框架应用程序中使用?