СУХОЙ с Rhino Mocks - PullRequest
       31

СУХОЙ с Rhino Mocks

6 голосов
/ 29 января 2010

Я ищу способы сделать следующее более лаконичным.

public class MyTests
{
    IPresenter presenter;

    [SetUp]
    public void SetUp()
    {
        presenter = MockRepository.GenerateStub<IPresenter>();
    }

    ...
}

В частности, повторное указание типа при создании макета представляется излишним. Например, я могу написать это так и использовать отражение, чтобы получить тип и автоматически создать заглушку:

public class MyTests
{
    IPresenter presenter;

    [SetUp]
    public void SetUp()
    {
        Stub(x => x.presenter);
    }

    void Stub(Expression<Func<MyTests, object>> expression)
    {
        ...
    }
}

Это будет работать, но компилятор больше не сможет определить, назначен ли докладчик, и начнет выдавать предупреждения. Это также делает ReSharper очень несчастным.

Кто-нибудь может предложить лучший подход?

Ответы [ 4 ]

5 голосов
/ 29 января 2010

Это может быть спорным, но я предпочитаю удобочитаемость, а не СУХОСТЬ * в модульных тестах.

Другими словами, методы настройки отсутствуют в моих модульных тестах. Они используются только для интеграционных тестов. Я считаю, XUnit.NET тоже занимает эту позицию.

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

** Естественно, мои юнит-тесты, скажем, в среднем на десять строк, если это увеличивается или объем настройки теста (в соответствии с AAA - Arrange, Act Assert) велик, только тогда я буду удалять дублирование и создавать вспомогательные методы , Чтобы прояснить это, для более чистых тестов вы можете создать базовый класс тестирования, который содержит вспомогательные методы и другой код настройки. *

3 голосов
/ 29 января 2010

Да, вообще не используйте [Setup] и переменные-члены, напишите Объекты Fixture вместо методов создания.

Объект Приспособления будет просто содержать соответствующий макет и другие части Приспособления.

Я лично использую AutoFixture в качестве объекта Fixture , и я настроил его как Auto-Mocking Container для загрузки, так что мне не нужно писать никакой фиктивный код, если только Мне нужно явно определить некоторое поведение.

Вот недавний пример модульного теста:

[TestMethod]
public void DeleteProductWillDeleteProductFromRepository()
{
    // Fixture setup
    var fixture = new ServiceFixture();
    var id = fixture.CreateAnonymous<int>();
    var repMock = fixture.FreezeMoq<ProductRepository>();

    var sut = fixture.CreateAnonymous<ProductManagementService>();
    // Exercise system
    sut.DeleteProduct(id);
    // Verify outcome
    repMock.Verify(r => r.DeleteProduct(id));
    // Teardown
}

В этом случае repMock создается Moq, но я мог бы настроить его на использование Rhino Mocks.

1 голос
/ 18 февраля 2011

У Майкла Фезерса (Michael Feathers) есть выдающееся представление об этом (см. Его презентацию http://www.ndc2010.no/index.aspx?id=361621). Создайте Builders и используйте это в тестах вместо всех видов установочных материалов.

Как:

    //The Class to Test
    public class ObjectY
    {
        public string DoThis(IObjectX objectX)
        {
            return objectX.id + objectX.name;
        }
    }


    [Test]
    //The test
    public void CreaeteTestData()
    {
        //Almost prosa style creation of test data 
        var testData = new ObjectXBuilder().WithId(123).WithName("ABC").Build();

        Assert.That(new ObjectY().DoThis(testData), Is.EqualTo("123ABC"));

    }


    //The Builder class - Provides easy creation testdata.
    internal class ObjectXBuilder
    {
        private MockRepository _mockRepository;
        private IObjectX _objectX;

        public ObjectXBuilder()
        {
            _mockRepository = new MockRepository();
            _objectX = _mockRepository.Stub<IObjectX>();
        }

        public ObjectXBuilder WithName(string name)
        {
            _objectX.name = name;
            return this;
        }

        public ObjectXBuilder WithId(long id)
        {
            _objectX.id = id;
            return this; 
        }

        public IObjectX Build()
        {
            _mockRepository.ReplayAll();
            return _objectX;
        }

    }
0 голосов
/ 29 января 2010

Общая проблема с C # в том, что он не выводит тип из результата метода (в отличие от Java), и это болезненно во многих ситуациях (просто приведу другой пример, где вы хотите реализовать метод десериализации) , Лично мне не нравится использовать ключевое слово var, потому что я хочу точно знать, какой тип моих объектов, я бы предпочел пропустить имя типа в шаблоне.

В любом случае, если мои тесты хорошие и маленькие, я склонен инициализировать все макеты внутри каждого теста. Таким образом, вы можете посмотреть на каждый тест отдельно от других тестов и сразу увидеть, что там происходит. Если они станут длиннее, хотя я просто использую мерзкий способ, который вы вставили в начале вашего вопроса.

...