2015-10-15 12 views
3

Я использую AutoFixture с AutoMoqCustomization и пытается создать экземпляр класса, который содержит только для чтения свойства, таким образом:AutoFixture AutoMoq не создавая издевается для некоторых свойств

public override ILog Logger { get; } = LogManager.GetLogger(typeof(MyService)); 

Идея заключается в том, что я должен быть в состоянии заморозить мой тест ILog тест двойного использования:

var log = fixture.Freeze<Mock<ILog>>; 

и убедитесь, что он был назван позже после основного вызова метода с помощью:

log.Verify(l => l.Warn, Times.Once); 

Однако, когда я звоню fixture.Create<MyService> AutoFixture не заменяет имущество Logger макету ILog. Я также попытался удалить значение по умолчанию LogManager.GetLogger<etc>, и в этом случае значение ILog равно null.

Другие свойства правильно заполнены тестовыми двойниками, но не этими.

Для справки, интерфейс ILog от рамок регистрации ServiceStack и выглядит следующим образом:

public interface ILog 
{ 
    bool IsDebugEnabled { get; } 
    void Debug(object message); 
    void Debug(object message, Exception exception); 
    void DebugFormat(string format, params object[] args); 
    void Error(object message); 
    void Error(object message, Exception exception); 
    void ErrorFormat(string format, params object[] args); 
    void Fatal(object message); 
    void Fatal(object message, Exception exception); 
    void FatalFormat(string format, params object[] args); 
    void Info(object message); 
    void Info(object message, Exception exception); 
    void InfoFormat(string format, params object[] args); 
    void Warn(object message); 
    void Warn(object message, Exception exception); 
    void WarnFormat(string format, params object[] args); 
} 

Я также проверил, что создание Mocks вручную и устанавливать их с Moq работает - свойство ILog правильно заменить с моим Mock использованием:

myServiceMock.Setup(s => s.Logger).Returns(myLoggerMock) 

Может ли кто-нибудь пролить свет на это?

Шаги по воспроизведению

Тест

using ServiceStack; 
    using ServiceStack.Logging; 
    using ServiceStack.Web; 
    using MyApp; 

    [Test] 
    public void LogTest() 
    { 
     var fixture = new Fixture().Customize(new AutoMoqCustomization()); 

     var log = fixture.Freeze<Mock<ILog>>(); 
     var request = fixture.Freeze<Mock<IRequest>>(); 
     var response = new Mock<IResponse>(); 
     var service = fixture.Create<MyService>(); 

     request.Setup(r => r.Response).Returns(response.Object); 

     service.Post(null); 

     log.Verify(l => l.Warn(It.IsAny<string>()), Times.Once()); 
    } 

Класс обслуживания - NB: Обычно Logger собственность будет суффиксом = LogManager.GetLogger(typeof(MyService)), но я опустил его в этот момент, чтобы этот вопрос ,

using ServiceStack; 
using ServiceStack.Logging; 

namespace MyApp 
{ 
    public class MyService : BaseService 
    { 
    public override ILog Logger { get; } 

    public MyResponse Post(MyRequest request) 
    { 
     if (request != null) return new MyResponse() {Message = request.Message}; 

     Logger.Warn("Null request object"); 
     return null; 
    } 
    } 

public abstract class BaseService : Service 
{ 
    public abstract ILog Logger { get; } 
} 

public class MyRequest 
{ 
    public string Message { get; set; } 
} 

public class MyResponse 
{ 
    public string Message { get; set; } 
} 
} 

Если останов на service.Post(null) линии вы увидите ILog свойства еще пустое, но и другие свойства имеют издеваются.

+0

Является ли класс с свойством «Logger» конкретным классом? AutoMoq не прокси-конкретные классы: http://blog.ploeh.dk/2010/08/25/ChangingthebehaviorofAutoFixtureauto-mockingwithMoq –

+0

Привет, Марк, это конкретный класс, поэтому я беру на себя суть, но если это так, то почему все другие свойства в том же классе, которые автоматически загружаются с помощью AutoMoq? – RNDThoughts

+1

Я не знаю, так как вы не показываете мне репродукцию ... –

ответ

4

Все, что делает AutoMoqCustomization, это настройка AutoFixture для делегирования всех запросов для интерфейсов или абстрактных типов в Moq. Он автоматически не устанавливает какие-либо заглушки для свойств и методов создаваемых двойников тестов.

Однако, как из AutoFixture 3.20.0 есть a new auto-mocking customization, что делает именно то, что: - AutoConfiguredMoqCustomization:

var fixture = new Fixture().Customize(new AutoConfiguredMoqCustomization()); 

Включение этой настройки гарантирует, что тест парный которые выходят из Moq настроены возвращать объекты, созданные AutoFixture из все их публичные свойства.

Но есть проблема.В качестве reported by @dcastro ошибка была introduced in Moq 4.2.1502.911, которая вызывает свойства только для чтения - как и свойство MyService.Logger в вашем случае - это будет отменено Moq после того, как AutoFixture настроит их.

Таким образом, даже если вы переключитесь на AutoConfiguredMoqCustomizationLogger свойство будет еще быть нулевым в силу того, что это только для чтения. С другой стороны, другие свойства и методы с возвращаемыми значениями будут настроены на возврат объектов, созданных AutoFixture.

Ваш лучший вариант сейчас - начать использовать AutoConfiguredMoqCustomization и перейти на earlier version of Moq, где свойства для чтения по-прежнему настроены правильно.

+1

Спасибо за вход Enrico, я последовал вашему предложению и понизил рейтинг, но все равно получаю тот же ответ (т. Е. Нулевое значение в свойстве Logger). Тем не менее, эти проблемы заставили меня пересмотреть мой код как структуру. Как отмечает @ mark-seemann в своем блоге, в моей структуре кода есть что-то принципиально неправильное, если мне нужно настроить тонну макетов, чтобы что-то проверить. Это не меняет того факта, что я по-прежнему не могу заставить его установить тестовый двойник для этого конкретного свойства по какой-то причине. – RNDThoughts

+0

Отмеченный ответ Энрико как правильный, хотя он не решает проблему, он указывает на проблему, которая может быть причиной. – RNDThoughts