学习c#单元测试



所以我试着用c#学习单元测试,我在网上找到了一个样本项目。项目在这里。

这是我第一次做单元测试,所以,我还在学习,遇到了一些错误。下面是我要测试的代码:

IRoosterService:

namespace MoqBusiness
{    
public interface IRoosterService
{
IList<Player> GetPlayersFromRepo();
}
}

RoosterService:

namespace MoqBusiness
{
public class RoosterService : IRoosterService
{
private readonly IPlayersRepo _players;
public RoosterService(IPlayersRepo players)
{
_players = players;
}

public IList<Player> GetPlayersFromRepo()
{
return _players.GetPlayerList();
}
}
}

IPlayersRepo:

namespace MoqDataRepos
{
public interface IPlayersRepo
{
IList<Player> GetPlayerList();
}
}

PlayersRepo:

namespace MoqDataRepos
{
public class PlayersRepo:IPlayersRepo
{ 
public IList<Player> GetPlayerList()
{
var playerList = new List<Player> {
new Player { Name = "Swaroop", Age = 28 ,PlayersClub = new Club{ ClubName = "Manchester United",CountryName = "GB",Position = 7} },
new Player { Name = "Seema", Age = 30 ,PlayersClub = new Club{ ClubName = "Manchester United",CountryName = "GB",Position = 7}},
new Player { Name = "Jay", Age = 35 ,PlayersClub = new Club{ ClubName = "Arsenal",CountryName = "GB",Position = 4}},
new Player { Name = "Don", Age = 30 ,PlayersClub = new Club{ ClubName = "Manchester City",CountryName = "GB",Position = 1}}
};
return playerList;
}
}
}

所以我试图测试这个RoosterService类开始,使用Moq和XUnit。

我的想法是我正在测试,看看GetPlayersFromRepo方法是否返回在PlayersRepo-GetPlayerList中的球员,所以我首先使用GetPlayersFromRepo方法,然后调用PlayersRepo-GetPlayerList方法,并比较两者,看看它们是否相等。

下面是我的测试代码:

namespace MoqTests
{
public class RoosterServiceTests
{
private readonly RoosterService _service;
private readonly Mock<IPlayersRepo> playersRepoMock = new Mock<IPlayersRepo>();
public RoosterServiceTests()
{
_service = new RoosterService(playersRepoMock.Object);
}

[Fact]
public void GetPlayersFromRepo_ShouldReturnPlayers()
{
//Arrange
var expected = playersRepoMock.Setup(p => p.GetPlayerList()).Returns(new List<Player>());

//Act
var players = _service.GetPlayersFromRepo();
//Assert
Assert.Equal(players, expected);
}
}
}

但是,这不起作用,因为出现以下错误消息

参数2:无法从' moq . language.com flow . ireturnnsresult'转换为'System.Collections.Generic.IEnumerable'

我不明白为什么会发生这种情况,因为这两个方法都返回一个列表,所以不确定为什么会发生此错误。因为这是我的第一次测试,我想我可能设置错了吗?如有任何建议,不胜感激。

首先,您不需要playersRepoMock.Setup的返回值,并且它返回的值可能不是您所期望的。

第二,在你的单元测试中,你会有这样的东西:
[Fact]
public void GetPlayersFromRepo_ShouldReturnPlayers()
{
//Arrange
var expected = new List<Player>();
playersRepoMock.Setup(p => p.GetPlayerList()).Returns(expected);

//Act
var players = _service.GetPlayersFromRepo();
//Assert
Assert.Equal(expected, players);
}

我建议这样做:

  • 命名
    • 使用Given When Then结构来描述测试用例
    • 使用expectedactual前缀来帮助可读性
    • 使用System Under Test(或简称sut)作为被测试对象的变量名
  • 技术的
    • 对于正常路径测试更倾向于使用非空集合
      • 空集合通常被认为是边缘或边缘情况
    • 确保你的模拟对象被按预期调用(Verify)
    • 在每个测试用例中重新创建模拟对象,使它们相互隔离(F.I.R.S.T.原则)
[Fact]
public void GivenAPlayerListWithASinglePlayer_WhenICallGetPlayersFromRepo_ThenItReturnsTheReposCollection()
{
//Arrange
var club = new Club { ClubName = "Manchester United", CountryName = "GB", Position = 7 };
var player = new Player { Name = "Swaroop", Age = 28 ,PlayersClub =  club };
var expectedPlayers = new List<Player> { player };
var playersRepoMock = new Mock<IPlayersRepo>();
playersRepoMock
.Setup(p => p.GetPlayerList())
.Returns(expectedPlayers);
var sut = new RoosterService(playersRepoMock.Object);

//Act
var actualPlayers = sut.GetPlayersFromRepo();
//Assert
playersRepoMock.Verify(p => p.GetPlayerList(), Times.Once);
Assert.Equal(expectedPlayers, actualPlayers);
}

根据你想要测试你的代码的防御程度,你可以有以下测试用例:

  • 确保没有新玩家被添加到列表
  • 确保没有现有的玩家被从列表中移除
  • 确保没有球员或俱乐部的信息被更改/篡改
  • 确保玩家的订单不变
  • 等。

注::如果你需要对集合执行断言,那么请使用FluentAssertions

相关内容

  • 没有找到相关文章

最新更新