2016-09-14 24 views
6

Tôi đang thử .NET Core lần đầu tiên và xem Moq có thể được sử dụng như thế nào trong thử nghiệm đơn vị. Ra khỏi hộp, các bộ điều khiển được tạo ra nơi ApplicationDbContext là các thông số để các nhà xây dựng như thế này:Làm cách nào để Moq ApplicationDbContext trong .NET Core

public class MoviesController : Controller 
{ 
    private readonly ApplicationDbContext _context; 

    public MoviesController(ApplicationDbContext context) 
    { 
     _context = context;  
    } 

Đây là bài kiểm tra đơn vị mà tôi bắt đầu với khi thử nghiệm bộ điều khiển:

[TestClass] 
public class MvcMoviesControllerTests 
{ 
    [TestMethod] 
    public async Task MoviesControllerIndex() 
    { 
     var mockContext = new Mock<ApplicationDbContext>();    
     var controller = new MoviesController(mockContext.Object); 

     // Act 
     var result = await controller.Index(); 

     // Assert 
     Assert.IsInstanceOfType(result, typeof(ViewResult)); 
    } 

Nhưng sau đó Tôi nhận ra ApplicationDbContext là một lớp cụ thể và nó không có một constructor parameterless nên test sẽ không hoạt động. Nó cho tôi lỗi: Không thể tìm thấy constructor parameterless.

Có lẽ đây có thể là một câu hỏi nhắm vào Moq hơn là liên quan đến .NET Core, nhưng tôi cũng mới với Moq nên tôi không chắc chắn cách tiếp tục. Đây là cách mã ApplicationDbContext được tạo khi tôi tạo dự án:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser> 
{ 
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) 
     : base(options) 
    { 
    } 

    protected override void OnModelCreating(ModelBuilder builder) 
    { 
     base.OnModelCreating(builder); 
     // Customize the ASP.NET Identity model and override the defaults if needed. 
     // For example, you can rename the ASP.NET Identity table names and more. 
     // Add your customizations after calling base.OnModelCreating(builder); 
    } 

    public DbSet<Movie> Movie { get; set; } 
} 

Tôi cần thay đổi gì để thử nghiệm đơn vị của mình thành công?

UPDATE:

tôi phát hiện ra từ https://msdn.microsoft.com/en-us/magazine/mt703433.aspx mà bạn có thể cấu hình EF Core để sử dụng một cơ sở dữ liệu trong bộ nhớ cho kiểm tra đơn vị. Vì vậy, tôi đã thay đổi thử nghiệm đơn vị của mình để trông giống như sau:

[TestMethod] 
    public async Task MoviesControllerIndex() 
    {   
     var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>(); 
     optionsBuilder.UseInMemoryDatabase(); 
     var _dbContext = new ApplicationDbContext(optionsBuilder.Options); 

     var controller = new MoviesController(_dbContext); 

     // Act 
     var result = await controller.Index(); 

     // Assert 
     Assert.IsInstanceOfType(result, typeof(ViewResult)); 
    } 

Thử nghiệm này hiện thành công. Nhưng đây có phải là cách thích hợp để làm điều này không? Rõ ràng, tôi hoàn toàn loại bỏ các Mocking ApplicationDbContext với Moq! Hoặc là có một giải pháp cho vấn đề này bằng cách sử dụng Moq.

+0

Ngay cả với bộ nhớ trong DbContext bạn về cơ bản đang thực hiện thử nghiệm tích hợp mà vẫn cần thiết. Tuy nhiên, bạn từ quan điểm thiết kế, nên có các lớp của bạn phụ thuộc vào trừu tượng và không phải concretions. Tạo một giao diện cho thấy các chức năng bạn cần và có bối cảnh cụ thể của bạn kế thừa từ đó. – Nkosi

+1

Tôi đồng ý với @Nkosi đây hiện là thử nghiệm tích hợp hiệu quả. Chắc chắn là 'ApplicationDbContext' thực hiện' IdentityDbContext ', bạn có thể đưa giao diện vào bộ điều khiển của bạn và sau đó giả lập nó thay thế không? – Corporalis

Trả lời

4

Bạn không nên cố gắng chế nhạo bối cảnh cơ sở dữ liệu trực tiếp. Thay vào đó, hãy triển khai Repository Pattern và giả lập kho lưu trữ thay thế.

Ở đây có một great guide về cách triển khai mẫu chính xác.

4

Giả mạo DbContext không hoạt động vì có quá nhiều nhà cung cấp được yêu cầu để làm cho nó hoạt động. Một giải pháp dễ dàng hơn nhiều là sử dụng giải pháp InMemory mà Microsoft đã thực hiện cho mục đích chính xác này. Xin vui lòng không tạo một repo chỉ để kiểm tra (mà vẫn không kiểm tra mã EF).

Dưới đây là một liên kết đến làm thế nào để kiểm tra với cơ sở dữ liệu InMemory trong lõi .net

https://docs.efproject.net/en/latest/miscellaneous/testing.html

1

Nếu ai đó có quan tâm, tôi nhận được một phần của ý tưởng về @Corporalis và thực hiện một giao diện để lộ ApplicationDbContext để dự án thử nghiệm.

public interface IApplicationDbContext 
{ 
    DbSet<Movie> Movies { get; set; } 

    int SaveChanges(); 
} 

Và trong ApplicationDbContext

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext 
{ 
    public virtual DbSet<Movie> Movies { get; set; } 

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) 
     : base(options) 
    { 
    } 

    protected override void OnModelCreating(ModelBuilder builder) 
    { 
     base.OnModelCreating(builder); 
    } 
} 

Đừng forguet để đăng ký Interface trong StartUp.cs, ConfigureServices

services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>()); 

Vì vậy, bây giờ trong điều khiển hoặc dịch vụ hoặc mỗi phương pháp mà bạn phải sử dụng ApplicationDbContext, làm điều đó một tham chiếu đến giao diện thay vì

public class filterMovies 
{ 
    private readonly IApplicationDbContext _context 

    public filterMovies(IApplicationDbContext context) 
    { 
    _context = context; 
    } 
} 

Bây giờ chúng ta sẽ cảm thấy tự do để nhạo báng các ApplicationDbContext sử dụng giao diện thay vì thực hiện nó tự

var mockContext = new Mock<IApplicationDbContext>(); 
mockContext.Setup(mc => mc.Movies).Returns(mockDbSet.Object); 

tôi hy vọng nó giúp;)

Các vấn đề liên quan