Мой тест moq для единицы работы не работает - PullRequest
0 голосов
/ 24 марта 2019

У меня есть контроллер, который имеет метод 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; }
}

Я связываю этот класс и интерфейс с помощью ниндоката IoC

 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);
    }

Я получаю сообщение

: Метод теста UnitTests.TestAdminController.TableCreamContainCreams вызвал исключение: System.NotSupportedException: Invalidнастройка для не виртуального (переопределяемого в VB) члена: uow => uow.Creams.GetAll

Что это значит и как написать правильный тест?Кто-нибудь может помочь?

1 Ответ

1 голос
/ 24 марта 2019

С Moq вы можете только макетировать интерфейсы и виртуальные методы.

Я думаю, у нас есть 2 варианта.

Один должен добавить ключевое слово virtual к GetAll свойству CreamRepository.

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

Затем добавьте еще Макет из 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);

Два составляют метод GetAll ICreamUOW и CreamUOW return ICreamRepository<CreamModel>

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 и Repository, должно быть что-то не так, потому что если мы тестируем фрагмент кода, который вызывает уровень A, который затем вызовет уровень B, нам нужно только смоделировать слой А.

Дайте мне знать, если это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...