je la configuration suivante:méthode Raillé DbSet lance NotImplementedException lorsqu'il est appelé à l'intérieur du contrôleur
DbContext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public virtual DbSet<Album> Album { get; set; }
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
Modèle:
public class Album
{
public int AlbumID { get; set; }
[StringLength(150)]
public string Title { get; set; }
}
Controller:
public class AlbumController : Controller
{
ApplicationDbContext db = new ApplicationDbContext();
public AlbumController(ApplicationDbContext injectDb)
{
db = injectDb;
}
// POST: Albums/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Admin")]
public ActionResult DeleteConfirmed(int id)
{
Album album = db.Album.Find(id);
db.Album.Remove(album);
db.SaveChanges();
return RedirectToAction("Index");
}
}
J'ai écrit le test unitaire en utilisant Moq et xUnit pour vérifier la fonctionnalité DeleteConfirmed:
public class AlbumsControllerTests
{
public static Mock<DbSet<T>> MockDbSet<T>(List<T> inputDbSetContent) where T : class
{
var DbSetContent = inputDbSetContent.AsQueryable();
var dbSet = new Mock<DbSet<T>>();
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(DbSetContent.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(DbSetContent.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(DbSetContent.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => inputDbSetContent.GetEnumerator());
dbSet.Setup(m => m.Add(It.IsAny<T>())).Callback<T>((s) => inputDbSetContent.Add(s));
dbSet.Setup(m => m.Remove(It.IsAny<T>())).Callback<T>((s) => inputDbSetContent.Remove(s));
return dbSet;
}
[Fact]
public void DeleteConfirmedTest()
{
// Arrange
var mockAlbumSet = MockDbSet(new List<Album> { });
Mock<ApplicationDbContext> sutDbContext = new Mock<ApplicationDbContext>() { CallBase = true };
sutDbContext.Setup(m => m.Album).Returns(mockAlbumSet.Object);
// Check if Album.Remove works inside this test
var albumToBeDeleted = new Album() { AlbumID = 1, Title = "TestAlbumName" };
sutDbContext.Object.Album.Add(albumToBeDeleted);
Assert.Equal(1, (from a in sutDbContext.Object.Album select a).Count());
sutDbContext.Object.Album.Remove(albumToBeDeleted);
Assert.Equal(0, (from a in sutDbContext.Object.Album select a).Count());
// Actual Test
sutDbContext.Object.Album.Add(albumToBeDeleted);
sutDbContext.Setup(m => m.Album.Find(It.IsAny<int>()))
.Returns(albumToBeDeleted);
AlbumController sut = new AlbumController(sutDbContext.Object);
var output = sut.DeleteConfirmed(1); // Throws NotImplementedException
// Assert
Assert.Equal(0, (from a in sutDbContext.Object.Album select a).Count());
}
}
Le test lève l'exception suivante sur db.Album.Remove (album) dans DeleteConfirmed:
System.NotImplementedException: Le membre 'Supprimer' n'a pas été mis en œuvre sur le type 'DbSet
1Proxy' which inherits from 'DbSet
1'. Le test double pour 'DbSet`1' doit fournir des implémentations de méthodes et propriétés utilisées.
Comme vous pouvez le voir dans le corps de la méthode MockDbSet, je configuration Remove méthode pour ma maquette et il fonctionne très bien à l'intérieur du test unitaire. Pouvez-vous m'expliquer pourquoi cela ne fonctionne pas dans le contrôleur?
Vous semblez injecter une implémentation de DbContext à votre contrôleur, pouvez-vous ajouter du code qui montre lequel? –
@raderick J'injecte ApplicationDbContext mock (vous pouvez vérifier son code source en haut). L'initialisation est dans le test: AlbumController (sutDbContext.Object). C'est le même DbContext que j'ai utilisé dans le corps du test. – Outshined
Le code de test semble globalement étrange, en lignes après '// Vérifier si Album.Remove fonctionne à l'intérieur de ce test' vous testez vos configurations fictives, ce qui est incorrect. Votre 'sut.DeleteConfirmed' teste également partiellement vos configurations Mock. Je vous conseille de passer votre DbSet à IDbSet et d'utiliser 'dbSetMock.Verify (x => x.Remove (albumToBeDeleted)) 'pour tester que le code est appelé sans tester les détails d'implémentation –