使用Moq进行单元测试LINQ to SQL CRUD操作

4

我查看了其他问题,但没有什么能完全符合我的要求......主要是因为我不确定自己在寻找什么!

基本上,我现在正在处理一个新项目,我已经创建了我的DB实体的抽象层并将DAC设置为存储库。我想使用单元测试和Mock对象,但是在CRUD(特别是C)操作方面遇到了智力壁垒,我的单元测试类:

[TestClass]
public class RepositoryTest
{
    private Mock<IPersonRepository> _repository;
    private IList<IPerson> _personStore;

    [TestInitialize()]
    public void Initialize()
    {
        _personStore= new List<IPerson>() {
            new Person() { Name = "Paul" },
            new Person() { Name = "John" },
            new Person() { Name = "Bob" },
            new Person() { Name = "Bill" },
        };

        _repository = new Mock<IPersonRepository>();
        _repository.Setup(r => r.Entirely()).Returns(_personStore.AsQueryable());
    }

    [TestCleanup()]
    public void Cleanup()
    {
        _personStore.Clear();
    }

    [TestMethod()]
    public void Can_Query_Repository()
    {
        IEnumerable<IPerson> people = _repository.Object.Entirely();
        Assert.IsTrue(people.Count() == 4);
        Assert.IsTrue(people.ElementAt(0).Name == "Paul");
        Assert.IsTrue(people.ElementAt(1).Name == "John");
        Assert.IsTrue(people.ElementAt(2).Name == "Bob");
        Assert.IsTrue(people.ElementAt(3).Name == "Bill");
    }

    [TestMethod()]
    public void Can_Add_Person()
    {
        IPerson newPerson = new Person() { Name = "Steve" };

        _repository.Setup(r => r.Create(newPerson));

        // all this Create method does in the repository is InsertOnSubmit(IPerson)
        // then SubmitChanges on the data context
        _repository.Object.Create(newPerson);

        IEnumerable<IPerson> people = _repository.Object.Entirely();
        Assert.IsTrue(people.Count() == 5);
    }
}

我的 Can_Query_Repository 方法成功了,但是 Can_Add_Person 方法无法通过断言。现在我需要做什么:

  1. 设置 Mock 存储库的 .Create 方法以将元素添加到 _personStore 中吗?
  2. 还需要类似的其他操作吗?
  3. 放弃所有希望,因为我想要实现的不可能,并且我做错了一切!

像往常一样,任何帮助/建议都将不胜感激!


只是一个快速的评论,解释为什么我的存储库返回方法是Entirely()。我的存储库名称是AllPeople,因此我可以拥有AllPeople.WhereAgeIs、AllPeople.WhereDOBIs和AllPeople.Entirely。 - Paul Aldred-Bann
1
你应该测试是否在模拟存储库接口中调用了Add/Save方法,而不是计数。 - AD.Net
你是指 .Verify() 方法吗?我刚试过了,如果我移除 .Count() 检查,测试会成功运行...不过这意味着什么呢?这个检查是否验证了方法的功能正常工作? - Paul Aldred-Bann
2
你可以通过某种集成测试来验证你确实将数据保存在真实的数据库中。但是对于单元测试,特别是当你模拟存储库时,你应该测试的只是你确实会使用正确的参数调用保存方法。否则,你将不得不创建某种框架,在其中添加所有对象,这有点违背了模拟存储库的目的。 - AD.Net
啊,那很有道理!是的,看起来我正在尝试在单元测试中测试整个东西 - 这不是一个单元测试!谢谢你,你应该将这个回复提交为答案,而不是评论,我会为你标记。干杯! - Paul Aldred-Bann
没问题,很高兴能帮忙 :)。干杯! - AD.Net
1个回答

7

理想情况下,您应该对它们进行一些集成测试,但如果您想进行单元测试,有可能的方法,包括原始问题评论中未提及的方法。

第一个方法。 在测试crud时,您可以使用.Verify来检查Create方法是否真正被调用。

mock.Verify(foo => foo.Execute("ping"));

使用Verify,您可以检查参数是某个特定类型的某个参数,并且方法实际调用的次数。如果您想验证已添加到存储库集合中的实际对象,您可以在模拟上使用.Callback方法。 在测试中创建一个列表来接收您创建的对象。然后在调用设置的同一行中添加回调,以将创建的对象插入列表中。 在断言中,您可以检查列表中的元素,包括它们的属性,以确保正确的元素已添加。
var personsThatWereCreated = new List<Person>(); 

_repository.Setup(r => r.Create(newPerson)).Callback((Person p) => personsThatWereCreated.Add(p));

// test code
// ...

// Asserts
Assert.AreEuqal(1, personsThatWereCreated.Count());
Assert.AreEqual("Bob", personsThatWereCreated.First().FirstName);

在您实际的例子中,您创建了一个人并将其添加到设置中。在这里使用回调方法是没有用处的。

您还可以使用此技术来增加一个变量以计算它被调用的次数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接