我有以下测试。
[TestFixture]
public class AdministratorRepositoryTests
{
private IAdministrateurRepository repository;
public static IAdministrateurRepository MockAdministrateurRepository(params Administrateur[] items)
{
var mockRepos = new Mock<IAdministrateurRepository>();
mockRepos.Setup(x => x.Select()).Returns(items.AsQueryable());
return (IAdministrateurRepository)mockRepos.Object;
}
[SetUp]
public void SetupContext()
{
Guid gId1 = new Guid("a05fd3de-9ae4-4b0b-b560-fd96678d3019");
Administrateur a1 = new Administrateur(gId1);
Guid gId2 = new Guid("e0724d12-d856-4677-89aa-d12611c15a4c");
Administrateur a2 = new Administrateur(gId2);
Guid gId3 = new Guid("30a69d49-84e5-42fc-a643-9e42c1350aa8");
Administrateur a3 = new Administrateur(gId3);
Guid gId4 = new Guid("b6444711-baee-4da6-87a8-a839c438bdff");
Administrateur a4 = new Administrateur(gId4);
Guid gId5 = new Guid("9d805acd-9d59-44ac-892c-438b189bbf94");
Administrateur a5 = new Administrateur(gId5);
repository = MockAdministrateurRepository(a1, a2, a3, a4, a5);
}
[Test]
public void peut_recuperer_un_administrateur_dun_repository_par_son_id()
{
Guid monGuid = new Guid("a05fd3de-9ae4-4b0b-b560-fd96678d3019");
var administrateur = repository.SelectById(monGuid);
administrateur.ShouldNotBeNull();
administrateur.Id.ShouldEqual(monGuid);
}
}
我很难理解为什么管理员返回NULL。
var administrateur = repository.SelectById(monGuid);
我甚至对存储库进行了计数测试,它有5个项目。
任何帮助?
答案 0 :(得分:7)
我经常看到这个问题 - 你从根本上误解了嘲弄/伪装/抄袭的目的是什么。也就是说,你正在编写一个虚假实现的测试,因此,测试是无用的。想一想 - 你的测试试图证明什么?您正在尝试验证是否可以从存储库中获取结果,但是:
// this is a mock/fake/stub/whatever, it's NOT the real class
var repository = new Mock<IAdministrateurRepository>();
// and so.. what is the point in this when your
// IAministratorRepository is not the production version?
var administrateur = repository.SelectById(monGuid);
// The repository is meant to be the focus of the test,
// yet you're not testing a result of using a real class
administrateur.ShouldNotBeNull();
administrateur.Id.ShouldEqual(monGuid);
以上一行是从您的存储库中提取数据,但存储库不是真正的实现。这不是生产代码。如果是这样,那么为什么然后断言从假存储库中取出的Administrator
对象呢?您正在测试的行为是ID功能搜索,但它是在您的测试夹具中定义的!您已经创建了一个存根/伪实现,然后对其进行了测试 - 仅此而已。 Mocks / Stubs / Fakes意味着有预期或提供预制结果来推动真实类型的测试(阅读:生产中使用的类型)。测试模拟本身没有任何效果。
在编写任何测试代码之前,您应该问自己此测试的目的是什么?如果您无法回答该问题,请在编写测试代码之前解决它。如果您要实际测试AdministratorRepository
,那么您将实例化存储库的生产代码版本,然后对其进行操作,然后在其行为的某些方面进行断言。
这blog post可能会对您有所帮助。我主张放弃模拟框架并使用基于状态的测试,直到你完全清楚模拟/存根适合的位置,因为它很容易被基于交互的测试弄糊涂。
*编辑 - 好的,这里(大致)代码应该是什么样子 忽略实现细节,只关注每种类型的角色,并注意它很简单。
// interface
public interface IAdministratorRepository
{
Administrator SelectById(Guid _id);
void Add(Administrator _admin);
}
// minimal implementation of admin.
public class Administrator
{
public Guid Id { get; set; }
public Administrator(Guid _id)
{
Id = _id;
}
}
/// <summary>
/// For argument's sakes, this is the class under test.
/// It's not a mock/fake/stub/whatever; it's the real deal!
/// </summary>
public class RealAdministratorRepository : IAdministratorRepository
{
private Dictionary<Guid, Administrator> m_items = new Dictionary<Guid, Administrator>();
public Administrator SelectById(Guid _id)
{
// no error handling here; keeping it simple
if(m_items.ContainsKey(_id))
return m_items[_id];
return null;
}
public void Add(Administrator _admin)
{
// No error handling for brevity's sakes
m_items.Add(_admin.Id, _admin);
}
}
// now, here's a very, very simple happy path test for SelectById using
// the real implementation of AdministratorRepository
[TestFixture]
public class AdministratorRepositoryTests
{
private const string AdminId = "a05fd3de-9ae4-4b0b-b560-fd96678d3019";
private IAdministratorRepository m_repository;
[SetUp]
public void PerTestSetUp()
{
// no mocks/stubs required. m_repository is a RealAdministratorRepository
// because that's our production class and that's what we want to test!
m_repository = new RealAdministratorRepository();
m_repository.Add(new Administrator(new Guid(AdminId)));
}
[Test]
public void SelectById_WithItemsInRepository_ReturnsCorrectItems()
{
// ignore the fact that I'm repeating the same string 3 times; brevity again
var item = m_repository.SelectById(new Guid(AdminId));
Assert.That(item, Is.Not.Null);
Assert.That(item.Id, Is.EqualTo(new Guid(AdminId)));
}
}
请注意,我没有使用模拟框架,因为我不需要。生产代码没有任何需要模拟/存根/伪造的有问题的依赖。
答案 1 :(得分:4)
模拟和伪造是两个不同的概念。您似乎认为您通过向其添加数据并期望数据存在来设置存储库。这就是假存储库的工作方式;它就像真正的存储库,但更简单,只包含您设置的数据。另一方面, mock 存储库实际上并不包含数据,但包含一组对具有特定签名的方法调用的响应。您设置了对没有参数的Select()
调用的响应,但实际上您正在使用特定参数调用SelectById()
调用。因为事先没有为此调用设置响应,所以它返回一个空结果,即当没有找到匹配的调用时的默认结果。
答案 2 :(得分:2)
您设置了Select
,但在测试中使用了SelectById
。
答案 3 :(得分:2)
您必须在MockAdministrateurRepository
方法中设置模拟存储库才能返回所需的Administarateur。
mockRepos
.Setup(x => x.SelectById(new Guid("a05fd3de-9ae4-4b0b-b560-fd96678d3019")))
.Returns(a1);