c# - unit - MoQ: la propiedad está configurada correctamente como virtual pero aún tiene una configuración no válida en un miembro no virtual
mocking entity framework when unit testing (1)
Me gustaría probar la unidad de un DbContext que hereda de IdentityDbContext
Recibo un mensaje de error NotSupportedException
con el mensaje muy común:
System.NotSupportedException: configuración no válida en un miembro no virtual (anulable en VB)
Para encontrar algunas pistas, ya leí un montón de publicaciones. Aquí hay algunas muestras:
Obviamente, la solución parece configurar el dbSet como virtual . Qué he hecho.
Mala suerte, el error permanece.
Aquí está mi IdentityDataContext :
public class IdentityDataContext : IdentityDbContext<ApplicationUser>
{
public virtual DbSet<Search> Searches { get; set; }
public IdentityDataContext()
: base("LocalDb",
throwIfV1Schema: true)
{
}
public static IdentityDataContext Create()
{
return new IdentityDataContext();
}
}
Aquí está mi búsqueda POCO:
public class Search : BaseEntity
{
//BaseEntity is just an abstract class with createdAt,Id,updatedAt property
public string ConsumerIdentifier { get; set; }
public string LanguageCode { get; set; }
}
Finalmente aquí está mi Método de Configuración :
[TestInitialize]
public void SetupTest()
{
//DataInitializer.GetAllSearches() returns a List of "Search"
_searches = DataInitializer.GetAllSearches();
var dbSet = new Mock<DbSet<Search>>();
dbSet.As<IQueryable<Search>>().Setup(m => m.Provider).Returns(_searches.AsQueryable().Provider);
dbSet.As<IQueryable<Search>>().Setup(m => m.Expression).Returns(_searches.AsQueryable().Expression);
dbSet.As<IQueryable<Search>>().Setup(m => m.ElementType).Returns(_searches.AsQueryable().ElementType);
dbSet.As<IQueryable<Search>>().Setup(m => m.GetEnumerator()).Returns(_searches.AsQueryable().GetEnumerator());
dbSet.Setup(d => d.Add(It.IsAny<Search>())).Callback<Search>(_searches.Add);
_dataContextMock = new Mock<IdentityDataContext>()
{
CallBase = true
};
// The error appears here ---------------- _
dataContextMock.Setup(x => x.Searches).Returns(dbSet.Object);
//----------------------------------------------------------------------
_dataContextMock.Setup(x => x.Set<Search>()).Returns(dbSet.Object);
_searchRepository = new SearchRepository(_dataContextMock.Object);
}
¿Qué me estoy perdiendo?
1) no es necesario probar la unidad DbContext. Microsoft ya lo habría probado extensamente.
2) si el DbContext se va a usar como una dependencia para otra clase, entonces abstrae el dbcontext
public interface IDataContext {
DbSet<Search> Searches { get; set; }
}
public class IdentityDataContext : IdentityDbContext<ApplicationUser>, IDataContext { ... }
public class SearchRepository {
public SearchRepository(IDataContext context) { ... }
}
No tengas clases dependiendo de las concreciones, sino de las abstracciones. IdentityDataContext
es un detalle de implementación que las clases dependientes no necesitan conocer.
Esto permitiría más flexibilidad para probar
Mock<IDataContext> _dataContextMock;
[TestInitialize]
public void SetupTest() {
//DataInitializer.GetAllSearches() returns a List of "Search"
_searches = DataInitializer.GetAllSearches();
var queryable = _searches.AsQueryable();
var dbSet = new Mock<DbSet<Search>>();
dbSet.As<IQueryable<Search>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<Search>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<Search>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<Search>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
dbSet.Setup(d => d.Add(It.IsAny<Search>())).Callback<Search>(_searches.Add);
_dataContextMock = new Mock<IDataContext>();
_dataContextMock.Setup(x => x.Searches).Returns(dbSet.Object);
_dataContextMock.Setup(x => x.Set<Search>()).Returns(dbSet.Object);
_searchRepository = new SearchRepository(_dataContextMock.Object);
}