模拟实体框架核心上下文

时间:2017-11-29 13:22:12

标签: c# entity-framework asp.net-core entity-framework-core

我尝试测试我的应用,所以我需要模拟我的EF上下文。

我的代码似乎没问题,但我有以下异常:

  

“System.ArgumentNullException:Value不能为null。参数名称:   源“

这是我的测试方法:

  var options = new DbContextOptionsBuilder<ProductContext>().Options;
    var settings = new SqlSettings
    {
        InMemory = true
    };

    var context = new Mock<ProductContext>(options, settings);
    var mockTreeService = new TreeService(context.Object);
    await mockTreeService.CreateTreeAsync("Testing tree", Guid.NewGuid());

    context.Verify(x => x.AddAsync(It.IsAny<Tree>(), CancellationToken.None), Times.Once);

看起来在执行这段代码时抛出了这个异常

            var tree = await _context.Trees
                .Include(x => x.Translation)
                .FirstOrDefaultAsync(x => x.Translation.Pl == name);

它来自我正在测试的服务

4 个答案:

答案 0 :(得分:17)

我认为这是由于没有设置连接字符串。坦率地说,完全模拟DbContext有点困难,这就是EF Core团队提供内存实现的原因。这对于测试目的而言更容易使用。只需将options初始化更改为:

即可
var options = new DbContextOptionsBuilder<ProductContext>()
                  .UseInMemoryDatabase(Guid.NewGuid().ToString())
                  .Options;

之后,您需要使用测试数据填充数据库。然后,您可以运行其余的测试。

注意:如果您正在使用内存数据库,则不再需要模拟上下文,因此您可以删除该位代码。内存数据库本身就是一个模拟。

答案 1 :(得分:2)

我已经使用了这个https://github.com/huysentruitw/entity-framework-core-mock库。非常容易,并且可以使用更少的编码来编写单元测试。

如果您使用的是Moq框架,则可以使用大多数Moq方法。

下面是测试DBQuery的示例代码。

CLASS lcl_alv DEFINITION.
  PUBLIC SECTION.
    METHODS:
      generate_alv.
  PRIVATE SECTION.
    DATA: o_salv_ida TYPE REF TO if_salv_gui_table_ida.
ENDCLASS.


START-OF-SELECTION.
  NEW lcl_alv( )->generate_alv( ).

CLASS lcl_alv IMPLEMENTATION.
  METHOD generate_alv.
    o_salv_ida = cl_salv_gui_table_ida=>create( iv_table_name = 'SBOOK' ).

    DATA(lo_layout) = o_salv_ida->default_layout( ).
    DATA(lt_sort_rule) = VALUE if_salv_gui_types_ida=>yt_sort_rule(
                       ( field_name = 'FLDATE'
                         descending = abap_false
                         is_grouped = abap_true ) ).
    lo_layout->set_sort_order( it_sort_order = lt_sort_rule ).

    DATA(lt_aggr_rules) = VALUE if_salv_gui_types_ida=>yt_aggregation_rule(
                       ( field_name = 'LUGGWEIGHT'
                         function   = if_salv_service_types=>cs_function_code-sum ) ).
    lo_layout->set_aggregations( lt_aggr_rules ).

    o_salv_ida->fullscreen( )->display( ).

  ENDMETHOD.
ENDCLASS.

在此处发布内容可能会对某人有所帮助:)

答案 2 :(得分:1)

我认为Mock DbContext是不正确的。您应该在测试中mocking repositoriesmocking DbContext是您基本上在测试Microsoft's代码...这很蠢,因为它们已经去做。因此,再次...所有数据访问都应通过repositories(请参阅Repository Pattern),而您应该是mocking测试中的用户,而不是DbContext

答案 3 :(得分:0)

尝试使用Moq / NSubstitute扩展名MockQueryable:https://github.com/romantitov/MockQueryable 支持所有同步/异步操作

//1 - create a List<T> with test items
var users = new List<UserEntity>()
{
 new UserEntity,
 ...
};

//2 - build mock by extension
var mock = users.AsQueryable().BuildMock();

//3 - setup the mock as Queryable for Moq
_userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object);

//3 - setup the mock as Queryable for NSubstitute
_userRepository.GetQueryable().Returns(mock);

还支持DbSet

//2 - build mock by extension
var mock = users.AsQueryable().BuildMockDbSet();

//3 - setup DbSet for Moq
var userRepository = new TestDbSetRepository(mock.Object);

//3 - setup DbSet for NSubstitute
var userRepository = new TestDbSetRepository(mock);

注意:

  • 从1.0.4版本开始支持AutoMapper
  • 从1.1.0版本开始支持
  • DbQuery