Подтвердить что ты не робот

Вызывающий общий вызов метода для любого заданного параметра типа

У меня есть интерфейс

public interface IDataProvider
{
    T GetDataDocument<T>(Guid document) where T:class, new()
}

Я хотел бы издеваться над этим так, что он просто вернет новый экземпляр заданного типа, независимо от точного типа, что-то вроде:

myMock.Setup(m => m.GetDataDocument<It.IsAny<Type>()>(It.IsAny<Guid>()))
.Returns(() => new T());

(это не работает, конечно, потому что я не могу просто указать параметр типа moq, и я не могу знать, какой тип должен быть возвращен.

Любые идеи по этому поводу?

4b9b3361

Ответ 1

Вместо использования макета, возможно, ваш случай будет лучше использовать Stub.

public class StubDataProvider : IDataProvider
{
    public T GetDataDocument<T>(Guid document) where T : class, new()
    {
        return new T();
    }
}

Если вам действительно нужен макет (так что вы можете проверить, что был вызван GetDataDocument). Вместо того, чтобы пытаться бороться с фреймворком Mocking, иногда проще просто создать класс Mock.

public class MockDataProvider : IDataProvider
{
    private readonly Action _action;

    public MockDataProvider(Action action)
    {
        _action = action;
    }

    public T GetDataDocument<T>(Guid document) where T : class, new()
    {
        _action();
        return new T();
    }
}

И чем в вашем тесте:

bool wasCalled = false;
IDataProvider dataProvider = new MockDataProvider(() => { wasCalled = true; });
var aTable = dataProvider.GetDataDocument<ATable>(new Guid());
Debug.Assert(wasCalled);

Ответ 2

Для конкретного теста, на который вы собираетесь использовать этот макет, вы, вероятно, знаете, что такое T, правильно?

просто настройте макет для этого:

myMock.Setup(m => m.GetDataDocument<MyDataClass>()>(It.IsAny<Guid>()))
   .Returns(() => new MyDataClass());

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

Ответ 3

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

Чтобы получить макетную работу, я добавил весь публичный тип в данную сборку во время выполнения.

//This is fairly expensive so cache the types
static DummyRepository()
{
    foreach( var type in typeof( SomeTypeInAssemblyWithModelObjects ).Assembly.GetTypes() )
    {
        if( !type.IsClass | type.IsAbstract || !type.IsPublic || type.IsGenericTypeDefinition )
        {
            continue;
        }

        g_types.Add( type );
    }
}

public DummyRepository()
{
    MockRepository = new Mock<ISomeRepository>();

    var setupLoadBy = GetType().GetMethod( "SetupLoadBy", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod );

    foreach( var type in g_types )
    {
        var loadMethod = setupLoadBy.MakeGenericMethod( type );
        loadMethod.Invoke( this, null );
    }
}

private void SetupLoadBy<T>()
{
    MockRepository.Setup( u => u.Load<T>( It.IsAny<long>() ) ).Returns<long>( LoadById<T> );
}

public T LoadById<T>( long id )
{
}