我的工作单元最小起订量测试不起作用

My moq test for unit of work doesn't work

我有控制器,它有方法GetAll(显示所有面霜)

public class AdminController : Controller
{
    private readonly ICreamUOW creamUOW;

    public AdminController( ICreamUOW creamUOW)
    {
        this.creamUOW = creamUOW;
    }

    [HttpGet]
    [Authorize(Roles = "Administrator")]
    public PartialViewResult TableCreams()
    {
        return PartialView(creamUOW.Creams.GetAll.ToList());
    }
}

我实现了我的存储库的工作单元模式

public class CreamUOW : ICreamUOW
{
    private readonly CreamEFDbContext contextDb;
    private CreamRepository creamRepository;

    public CreamUOW()
    {
        this.contextDb = new CreamEFDbContext();
    }

    //properties
    public CreamRepository Creams
    {
        get
        {
            if (creamRepository == null)
                creamRepository = new CreamRepository(contextDb);
            return creamRepository;
        }
    }
}

和他的界面

public interface ICreamUOW : IDisposable
{
    CreamRepository Creams { get; }
}

我通过 ninject IoC

绑定此 class 和接口
 kernel.Bind<ICreamUOW>().To<CreamUOW>();

(我只展示方法,属性有问题的地方,我在项目中实现了一个dispose方法,不过现在不重要了)

我的通用存储库界面

public interface ICreamRepository<T> where T : class
{
    //property
    IEnumerable<T> GetAll { get; }
}

和他的实现

public class CreamRepository : ICreamRepository<CreamModel>
{
    private CreamEFDbContext context;

    public CreamRepository(CreamEFDbContext dbContext)
    {
        context = dbContext;
    }

    public IEnumerable<CreamModel> GetAll
    {
        get { return context.CreamModels.Include(x => x.CreamTypeModel); }
    }
}

我尝试进行测试,但它不起作用

[TestMethod]
    public void TableCreamContainCreams()
    {
        //arrange
        List<CreamModel> creams = new List<CreamModel>()
        {
            new CreamModel () { Id = 1, Name = "Test te1", Description = "1" },
            new CreamModel () { Id = 2, Name = "Test te2", Description = "2" }
        };

        private Mock<ICreamUOW> mockCreamUOW = new Mock<ICreamUOW>();
        mockCreamUOW.Setup(uow => uow.Creams.GetAll).Returns(creams.ToList());

        AdminController controller = new AdminController(null, null, mockCreamUOW.Object);

        //action
        PartialViewResult resultView = controller.TableCreams();

        //assert
        Assert.AreEqual(((List<CreamModel>)resultView.Model).Count(), 2);
        Assert.IsTrue(((List<CreamModel>)resultView.Model).Count(p => p.Description == "1") == 1);
    }

我拿

Message: Test method UnitTests.TestAdminController.TableCreamContainCreams threw exception: System.NotSupportedException: Invalid setup on a non-virtual (overridable in VB) member: uow => uow.Creams.GetAll

这是什么意思以及如何编写正确的测试?有人可以帮忙吗?

您只能使用 Moq 模拟接口和虚拟方法。

我想我们有两个选择。

一个是在CreamRepositoryGetAll属性中添加virtual关键字。

public virtual IEnumerable<CreamModel> GetAll
{
    get
    {
        return context.CreamModels.Include(a => a.CreamTypeModel);
    }
}

然后在单元测试中添加另一个 Mock of CreamRepository

// A mock of CreamRepository, with null passed in because the constructor wants it
Mock<CreamRepository> mockCreamRepository = new Mock<CreamRepository>(null);

// which will return fake data
mockCreamRepository.Setup(mcr => mcr.GetAll).Returns(creams);

// Calling Creams on Mock UOW will give us Mock CreamRepository
// which will in turn give us the fake data if its GetAll is called. 
mockCreamUOW.Setup(uow => uow.Creams).Returns(mockCreamRepository.Object);

两个ICreamUOWCreamUOWreturnICreamRepository<CreamModel>[=21的GetAll方法=]

public class CreamUOW : ICreamUOW
{
    // No changes to the rest of your code
    public ICreamRepository<CreamModel> Creams
    {
    }
}

public interface ICreamUOW : IDisposable
{
    // So your interface will be
    ICreamRepository<CreamModel> Creams { get; }
}

还有你的单元测试

// Now we are mocking an interface instead of a concrete class like above
Mock<ICreamRepository<CreamModel>> mockCreamRepository = new Mock<ICreamRepository<CreamModel>>();
// The rest is the same
mockCreamRepository.Setup(mcr => mcr.GetAll).Returns(creams);
mockCreamUOW.Setup(uow => uow.Creams).Returns(mockCreamRepository.Object);

但是,正如@sellotape 指出的那样,我不熟悉你对 UOW 和存储库的实现,肯定有问题,因为如果我们正在测试一段调用 A 层的代码,A 层将调用 A 层B,我们应该只需要模拟A层。

如果有帮助请告诉我。