在 ASP.NET Web API 中是否需要模拟连接到工作单元的存储库以进行单元测试?

Does the Repository connected to a Unit of Work need to be mocked for Unit Testing in ASP.NET Web API?

我有一个工作单元模式和一个 Repo 模式来与数据库层交互(Entity Framework 在这种情况下),然后我在控制器的构造函数中进行依赖注入。我的问题是,所以 我模拟了一个 IUnitOfWork,它是控制器与之交互的东西,但是,工作单元 class 实际上访问了存储库,所以我也必须模拟一个存储库,如果那么,我该如何实现呢? 我正在尝试完成基本的 Get 控制器方法的单元测试。我已经阅读和观看了几个小时的视频和文章,这是我目前所拥有的:

class UrlControllerTests
    {
        [TestMethod]
        public void ShouldReturnUrlList()
        {

            Mock<IUnitOfWork> fakeUnitOfWork = new Mock<IUnitOfWork>();
            var urlController = new UrlController(fakeUnitOfWork.Object);

        urlController.Get(5); //All this is just to see if we can get thru a test.
        Assert.IsTrue(true);
        }

IRepo

public interface IRepo<TEntity> where TEntity: class
    {
        TEntity Get(int id);
        IEnumerable<TEntity> GetAll();
        //Allows the running of lamba-style LINQ queries like the typical Entity Framework does:
        IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);

        void Add(TEntity entity);
        void AddRange(IEnumerable<TEntity> entities);

        void Remove(TEntity entity);
        void RemoveRange(IEnumerable<TEntity> entities);
    }

IUnitOfWork:

public interface IUnitOfWork :IDisposable {
    IRepo<Url> Urls { get; }
    int Complete();
}

工作单位:

public class UnitOfWork : IUnitOfWork
    {
        private readonly ApplicationDbContext _context;
        public IRepo<Url> Urls { get; set; }
        public UnitOfWork(ApplicationDbContext context)
        {
            _context = context;
            Urls = new Repo<Url>(_context);

        }

        public int Complete()
        {
            return _context.SaveChanges();
        }

        public void Dispose()
        {
            _context.Dispose();
        }
    }

回购:

public class Repo<TEntity> : IRepo<TEntity> where TEntity : class
    {
        protected readonly ApplicationDbContext _context;

        public Repo(ApplicationDbContext context)
        {
            _context = context;
        }

        public TEntity Get(int id)
        {
            return _context.Set<TEntity>().Find(id);
        }
        //Repositories SHOULD NOT return IQueryable because otherwise other resources may
        //Try to build queries
        public IEnumerable<TEntity> GetAll()
        {
            return _context.Set<TEntity>().ToList();
        }

        public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
        {
            return _context.Set<TEntity>().Where(predicate);
        }

        public void Add(TEntity entity)
        {
            _context.Set<TEntity>().Add(entity);
        }

        public void AddRange(IEnumerable<TEntity> entities)
        {
            _context.Set<TEntity>().AddRange(entities);
        }

        public void Remove(TEntity entity)
        {
            _context.Set<TEntity>().Remove(entity);
        }

        public void RemoveRange(IEnumerable<TEntity> entities)
        {
            _context.Set<TEntity>().RemoveRange(entities);
        }
    }
}

我正在使用最小起订量。

编辑:我要测试的内容:

public IHttpActionResult Get(int id)
        {
            var url = _unitOfWork.Urls.Get(id);
            if (url == null)
            {
                NotFound();
            }
            return Ok(url);
        }

被测目标方法依赖于 IUnitOfWorkIRepo<Url>。在创建单元测试时,您通常会模拟被测系统的依赖项,以便可以在没有依赖项调用实际实现(集成测试)的情况下对其进行隔离测试。

[TestClass]
public class UrlControllerTests {
    [TestMethod]
    public void Get_With_Valid_Id_Should_Return_Url() {
        //Arrange
        var testId = 5;
        var expected = new Url { Id = testId };

        var mockRepo = new Mock<IRepo<Url>>();
        mockRepo.Setup(m => m.Get(testId)).Returns(expected);

        var mockUnitOfWork = new Mock<IUnitOfWork>();
        mockUnitOfWork.Setup(m => m.Urls).Returns(mockRepo.Object);

        var sut = new UrlController(mockUnitOfWork.Object);

        //Act
        var actionResult = sut.Get(testId) as OkNegotiatedContentResult<Url>; 

        //Assert
        Assert.IsNotNull(actionResult);
        Assert.AreEqual(expected, actionResult.Content);
    }
}

Moq 足够灵活,您还可以模拟整个依赖项调用,这样如果您不需要更复杂的设置,就不必模拟存储库。

然后测试将被重写为

[TestClass]
public class UrlControllerTests {
    [TestMethod]
    public void Get_With_Valid_Id_Should_Return_Url() {
        //Arrange
        var testId = 5;
        var expected = new Url { Id = testId };

        var mockUnitOfWork = new Mock<IUnitOfWork>();
        mockUnitOfWork.Setup(m => m.Urls.Get(testId)).Returns(expected);

        var sut = new UrlController(mockUnitOfWork.Object);

        //Act
        var actionResult = sut.Get(testId) as OkNegotiatedContentResult<Url>; 

        //Assert
        Assert.IsNotNull(actionResult);
        Assert.AreEqual(expected, actionResult.Content);
    }
}