Moq,ASP .NET MVC如何进行模块测试

时间:2019-01-11 11:27:02

标签: c# asp.net-mvc moq

我有一个方法,它向我返回返回视图做ajax操作,如何测试它以检查正确的数据返回与否?

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

enter image description here

当我从下拉列表中选择一个团队时,我以string name来发布,

1)如果"Все игроки"我和所有玩家一起进入桌子

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

登机测试如何将所有玩家或团队中的某些玩家返回?

1 个答案:

答案 0 :(得分:2)

您是否尝试过简单地调用该方法并检查响应?关于MVC框架的好处是,您不需要只需要使用控制器就可以使用整个框架。堆栈中的其他组件将采用ActionResult并将其呈现为HTML。

PartialView返回一个PartialViewResult,其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 questionsEF documentation中。

EF Core 通过其in-memory database provider使模拟变得更加容易。 EF Core与.NET运行时无关,这意味着它也可以在完整框架应用程序中使用。文档中的Testing with InMemory包含更详细的示例。还有一个示例显示了using SQLite for more advanced scenarios

懒惰,我假设存储库是实现接口的类:

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

创建一个模拟类很容易,它可以接受列表,数组或播放器,并通过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对于更复杂的界面很有用。使用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);
    ...
}

“经典” 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可以在Full Framework应用程序中使用?