Администратор возвращает ноль, но почему? - PullRequest
2 голосов
/ 19 февраля 2011

У меня есть следующий тест.

[TestFixture]
    public class AdministratorRepositoryTests
    {
        private IAdministrateurRepository repository;

        public static IAdministrateurRepository MockAdministrateurRepository(params Administrateur[] items)
        {
            var mockRepos = new Mock<IAdministrateurRepository>();
            mockRepos.Setup(x => x.Select()).Returns(items.AsQueryable());
            return (IAdministrateurRepository)mockRepos.Object;
        }

        [SetUp]
        public void SetupContext()
        {
            Guid gId1 = new Guid("a05fd3de-9ae4-4b0b-b560-fd96678d3019");
            Administrateur a1 = new Administrateur(gId1);

            Guid gId2 = new Guid("e0724d12-d856-4677-89aa-d12611c15a4c");
            Administrateur a2 = new Administrateur(gId2);

            Guid gId3 = new Guid("30a69d49-84e5-42fc-a643-9e42c1350aa8");
            Administrateur a3 = new Administrateur(gId3);

            Guid gId4 = new Guid("b6444711-baee-4da6-87a8-a839c438bdff");
            Administrateur a4 = new Administrateur(gId4);

            Guid gId5 = new Guid("9d805acd-9d59-44ac-892c-438b189bbf94");
            Administrateur a5 = new Administrateur(gId5);

            repository = MockAdministrateurRepository(a1, a2, a3, a4, a5);

        }

        [Test]
        public void peut_recuperer_un_administrateur_dun_repository_par_son_id()
        {
            Guid monGuid = new Guid("a05fd3de-9ae4-4b0b-b560-fd96678d3019");

            var administrateur = repository.SelectById(monGuid);

            administrateur.ShouldNotBeNull();
            administrateur.Id.ShouldEqual(monGuid);
        }
    }

Я изо всех сил пытаюсь понять, ПОЧЕМУ администратор возвращает NULL.

var administrateur = repository.SelectById(monGuid);

Я даже провел подсчет в хранилище, и оноимеет 5 предметов.

Любая помощь?

Ответы [ 4 ]

7 голосов
/ 19 февраля 2011

Я часто вижу эту проблему - вы в корне не понимаете, в чем заключается цель насмешек / фальсификаций / окурков.То есть вы пишете тест для поддельной реализации, и в результате тест бесполезен .Подумайте об этом - что ваш тест пытается доказать?Вы пытаетесь проверить, что можете получить результаты из репозитория, но:

// this is a mock/fake/stub/whatever, it's NOT the real class
var repository = new Mock<IAdministrateurRepository>(); 

// and so.. what is the point in this when your 
// IAministratorRepository is not the production version?
var administrateur = repository.SelectById(monGuid);

// The repository is meant to be the focus of the test, 
// yet you're not testing a result of using a real class
administrateur.ShouldNotBeNull();
administrateur.Id.ShouldEqual(monGuid);

Приведенная выше строка извлекает данные из вашего репозитория, но репозиторий не является реальной реализацией.Это не производственный код.Если так, то почему вы тогда утверждаете на объекте Administrator, который извлекается из поддельного хранилища?Поведение, которое вы тестируете, - это функция поиска по идентификатору, но она определяется внутри вашего тестового устройства!Вы создали заглушенную / фальшивую реализацию, а затем протестировали ее - больше ничего.Предполагается, что Mocks / Stubs / Fakes должны иметь ожидания или предоставлять постоянные результаты для тестирования реальных типов (читай: типы, используемые в производстве).Тестирование самого макета ничего не дает.

Прежде чем писать какой-либо тестовый код, вы должны спросить себя Какова цель этого теста? Если вы не можете ответить на этот вопрос, разрешите его раньшеВы пишете тестовый код.Если бы вы на самом деле тестировали ваш AdministratorRepository, вы бы создали экземпляр рабочей версии кода репозитория, а затем манипулировали им, а затем утверждали какой-то аспект его поведения.

Это сообщение в блоге может помочь вам.Я бы выступил за отказ от использования основ mocking и использования тестирования на основе состояния, пока вы не будете полностью уверены в том, куда вписывается mocking / stubbing, так как тестирование на основе взаимодействия легко запутать.

* edit - Хорошо, вот (примерно) как должен выглядеть ваш код Игнорируйте детали реализации, просто сосредоточьтесь на ролях каждого типа и обратите внимание, что это просто, как может быть.

// interface
public interface IAdministratorRepository
{
    Administrator SelectById(Guid _id);
    void Add(Administrator _admin);
}

// minimal implementation of admin.  
public class Administrator
{
    public Guid Id { get; set; }

    public Administrator(Guid _id)
    {
        Id = _id;
    }
}

/// <summary>
/// For argument's sakes, this is the class under test.  
/// It's not a mock/fake/stub/whatever; it's the real deal!
/// </summary>
public class RealAdministratorRepository : IAdministratorRepository
{
    private Dictionary<Guid, Administrator> m_items = new Dictionary<Guid, Administrator>();

    public Administrator SelectById(Guid _id)
    {
        // no error handling here; keeping it simple
        if(m_items.ContainsKey(_id))
            return m_items[_id];

        return null;
    }

    public void Add(Administrator _admin)
    {
        // No error handling for brevity's sakes
        m_items.Add(_admin.Id, _admin);
    }
}

// now, here's a very, very simple happy path test for SelectById using
// the real implementation of AdministratorRepository
[TestFixture]
public class AdministratorRepositoryTests
{
    private const string AdminId = "a05fd3de-9ae4-4b0b-b560-fd96678d3019";
    private IAdministratorRepository m_repository;

    [SetUp]
    public void PerTestSetUp()
    {
        // no mocks/stubs required.  m_repository is a RealAdministratorRepository
        // because that's our production class and that's what we want to test!
        m_repository = new RealAdministratorRepository();
        m_repository.Add(new Administrator(new Guid(AdminId)));
    }

    [Test]
    public void SelectById_WithItemsInRepository_ReturnsCorrectItems()
    {
        // ignore the fact that I'm repeating the same string 3 times; brevity again
        var item = m_repository.SelectById(new Guid(AdminId));

        Assert.That(item, Is.Not.Null);
        Assert.That(item.Id, Is.EqualTo(new Guid(AdminId)));
    }
}

Обратите внимание, что яне использую насмешливые рамки, потому что мне это не нужно.Производственный код не имеет проблемных зависимостей, которые требуют насмешек / заглушек / подделок.

4 голосов
/ 19 февраля 2011

Насмешка и подделка - это две разные концепции.Кажется, вы думаете, что настраиваете репозиторий, добавляя в него данные и ожидая, что эти данные будут там.Вот как работает поддельный репозиторий;это как настоящий репозиторий, но гораздо проще и содержит только те данные, с которыми вы его настроили.С другой стороны, репозиторий mock на самом деле не содержит данных, но содержит набор ответов на вызовы методов с конкретными сигнатурами.Вы настраиваете ответ на вызов Select() без параметров, но фактически вызываете вызов SelectById() с определенным параметром.Поскольку для этого вызова предварительно не настроен ответ, он возвращает нулевой результат, т. Е. Значение по умолчанию, когда не удается найти соответствующий вызов.

2 голосов
/ 19 февраля 2011

Вам необходимо настроить репозиторий в вашем методе MockAdministrateurRepository, чтобы вернуть нужного администратора.

mockRepos
    .Setup(x => x.SelectById(new Guid("a05fd3de-9ae4-4b0b-b560-fd96678d3019")))
    .Returns(a1);
2 голосов
/ 19 февраля 2011

Вы настроили Select, но в тесте используете SelectById.

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