如何通过 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 可以在完整框架应用程序中使用?
我有一个方法,它 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 通过其
因为懒惰,我假设存储库是一个 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 可以在完整框架应用程序中使用?