c# - 模拟存储库和测试参数化服务方法

标签 c# unit-testing mocking expression moq

我花了几天时间寻找解决方案,该解决方案允许我模拟由 Expression<Func<T, bool>> 参数化的方法。 。我发现this 。但不幸的是,当我想使用字符串参数测试服务方法时,它不起作用,例如:public IEnumerable<Person> FindByName(string name) ,如下所示:

using System;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace UnitTestProject
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            var mock = new Mock<IRepository<Person>();

            mock.Setup(r => r.Find(AreEqual<Person>(p => p.FirstName.Equals("Justin")))).Returns(new[]
                {
                    new Person {FirstName = "Justin", LastName = "Smith"},
                    new Person {FirstName = "Justin", LastName = "Quincy"}
                });

            var personService = new PersonService(mock.Object);
            Person[] justins = personService.FindByName("Justin").ToArray();
            Person[] etheredges = personService.FindByName("Etheredge").ToArray();

            Debugger.Break();
        }

        static Expression<Func<T, bool>> AreEqual<T>(Expression<Func<T, bool>> expr)
        {
            return Match.Create<Expression<Func<T, bool>>>(t => t.ToString() == expr.ToString());
        }
    }

    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public interface IRepository<T>
    {
        IEnumerable<T> Find(Expression<Func<Person, bool>> predicate);
    }

    public class PersonService
    {
        readonly IRepository<Person> _repository;

        public PersonService(IRepository<Person> repository)
        {
            _repository = repository;
        }

        public IEnumerable<Person> FindByName(string name)
        {
            return _repository.Find(p => p.FirstName.Equals(name));
        }
    }
}

当调试器中断时,我期望数组 justins将包含上面列出的两项和数组 etheredges将不包含任何项目。实际上它们都是空数组。我怀疑它发生是因为 FindByName方法中,字符串不是直接提供的,而是通过变量 name 提供的.

你知道如何解决这个问题吗?

最佳答案

假设您只想测试服务的 Find 逻辑(并且您信任 LINQ :-)),您可以做的就是编译传入的 Expression 谓词并在假存储库中执行表达式(即 pred => fakePeople.Where(pred.Compile()));):

  [TestMethod]
  public void TestMethod1()
  {
     var mock = new Mock<IRepository<Person>>();

     var fakePeople = new[]
          {
             new Person {FirstName = "Justin", LastName = "Smith"},
             new Person {FirstName = "Justin", LastName = "Quincy"},
             new Person {FirstName = "Joe", LastName = "Bloggs"}
          };

     mock.Setup(r => r.Find(It.IsAny<Expression<Func<Person, bool>>>()))
         .Returns<Expression<Func<Person, bool>>>(
             pred => fakePeople.Where(pred.Compile()));

     var personService = new PersonService(mock.Object);

     var searchForJustins = personService.FindByName("Justin");
     Assert.AreEqual(2, searchForJustins.Count());
     Assert.IsTrue(searchForJustins.Any(_ => _.LastName == "Quincy") 
           && searchForJustins.Any(_ => _.LastName == "Smith"));

     var searchForEtheredges = personService.FindByName("Etheredge");
     Assert.IsFalse(searchForEtheredges.Any());
  }

次要,但存储库代码本身无法编译 - 我假设您有一个通用的存储库模式:

   public interface IRepository<T>
   {
      IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
   }

   public class PersonService
   {
      readonly IRepository<Person> _repository;

      public PersonService(IRepository<Person> repository)
      {
         _repository = repository;
      }

      public IEnumerable<Person> FindByName(string name)
      {
         return _repository.Find(p => p.FirstName.Equals(name));
      }
   }

关于c# - 模拟存储库和测试参数化服务方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23251512/

相关文章:

c# - 考虑到语言环境,是否可以在 LINQ 查询中回退空值?

c# - 通用 InBetween 函数

visual-studio - 有关Visual Studio 2005的单元测试,是否有详细的“方法”

c# - 关于单元测试的好资源?

c# - LINQ OrderByDescending 到 OrderByAscending?

c# - 如何让Windows 8.1应用程序进入可视状态?

c# - EF linq模拟中临时创建的表中的异常

c# - NServiceBus 处理程序单元测试的依赖注入(inject)

java - 模拟与实现。如何在单个测试类中共享这两种方法?

python - 如何测试我是否正确调用了 pickle.dump()?