2011-03-15 10 views
36

tengo una interfazque imita llamada a un método genérico para cualquier tipo determinado parámetro

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

me gustaría burlarse de una manera, que acaba de regresar de una nueva instancia de un tipo determinado, independientemente de la tipo exacto, algo así como:

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

(que no funciona, por supuesto, porque no puedo dar ningún parámetro de tipo de mOQ, y no puedo saber a qué se debe devolver el tipo

cualquier. ideas sobre este?

Respuesta

25

En lugar de utilizar un simulacro, tal vez su caso sería mejor utilizar un Stub.

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

Si realmente necesita una maqueta (para que pueda verificar que GetDataDocument se llamaba). En lugar de tratar de luchar con un marco de burla, a veces es más fácil crear una clase falsa a la derecha.

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

Y que en su prueba:

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

solución, aunque me gustaría ver algún marco simulado/stub hacer esto automágicamente :) Voy a tratar de esperar un poco, tal vez otra respuesta se inclinará con una solución auotomatic. – Hassan

11

Para la prueba en particular que va a utilizar este simulacro, probablemente sepa qué será T, ¿no?

simplemente configurar el simulacro de que:

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

No es muy recomendable para reutilizar los simulacros de todos modos, así que adelante y se burla de configuración para la prueba real en la mano.

+19

no, el punto es, que no sé el tipo exacto, sé que serán utilizados varios tipos, pero estoy demasiado vago para escribir diferentes cláusulas de configuración para todos :) Buena – Hassan

4

tuve un problema similar, he elegido contra el uso de un talón en esta situación, ya que no quiero adiciones a la interfaz está probando para requerir cambios inmediatos para el código de prueba. es decir, agregar un nuevo método no debería romper mis pruebas existentes.

Para obtener el simulacro de trabajo agregué todo el tipo público en un conjunto determinado en tiempo de ejecución.

//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) 
{ 
} 
Cuestiones relacionadas