对存储库进行单元测试-如何在.Net Core中处理模拟服务和dbcontext?

时间:2020-01-15 23:46:58

标签: c# unit-testing asp.net-core repository dbcontext

我正在尝试对一个相对简单的存储库进行单元测试,但是我很难找出处理存储库需要实例化的服务和数据库上下文的最佳方法。

存储库有一个公共方法,该方法返回一个Member对象:

public class MemberRepository : IMemberRepository
{
    private OServiceContext _openService;
    private OpenDbContext _openDbContext;

    public MemberRepository(OServiceContext openService, OpenDbContext openDbContext)
    {
        _openService = openService;
        _openDbContext = openDbContext;
    }

    public async Task<Member> GetMember(int policyMemberId, int policyActivityId)
    {
        Member member = null;

        var members = await _openDbContext.PolicyMembers
            .Include(c => c.Contact)
            .SingleOrDefaultAsync(x => x.PolicyActivityKey == policyActivityId && x.PolicyMemberKey == policyMemberId);

        if (members != null)
        {
            member = ConvertDataToMember(members);
        }

        return member;
    }}

ServiceContext整理了四个不同的服务,这些服务的用途在CTOR中相对明确:

public OServiceContext(OpenConfiguration config)
    {
        _username = config.Username;
        _password = config.Password;

        _authenticationService = new AuthenticationService(config.GetEndpointConfigurationFor(nameof(AuthenticationService)));
        _dataService = new DataService(config.GetEndpointConfigurationFor(nameof(DataService)));
        _workflowService = new WorkflowService(config.GetEndpointConfigurationFor(nameof(WorkflowService)));
        _documentService = new DocumentService(config.GetEndpointConfigurationFor(nameof(DocumentService)));

        var viewClasses = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(x => x.GetTypes())
            .Where(x => typeof(IOpenHostView).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract && x.IsPublic)
            .Select(x => x)
            .ToList();

        foreach (var c in viewClasses)
        {
            var attribute = c.GetCustomAttributesData()
                .FirstOrDefault(x => x.AttributeType == typeof(OpenViewAttribute));

            if (attribute == null)
                throw new NullReferenceException($"Unable to find '{nameof(OpenViewAttribute)}' on {nameof(IOpenView)} implementation $'{c.Name}'.");

            var viewName = attribute.ConstructorArguments[0].Value.ToString();
            var viewConfig = config.GetViewConfigurationFor(viewName);

            if (viewConfig == null)
                throw new NullReferenceException($"Unable to locate key for Open view '{viewName}'.");

            _viewLookup.Add(c, viewConfig.Key);
        }
    }

目前的测试:

    [Fact]
    public void MemberRepository_GetMember_ReturnsValidMember()
    {
        //Arrange

        var mockOServiceConfig = new OpenConfiguration()
        {
            Username = "test",
            Password = "pass",
            Remoting = new OpenRemotingConfiguration(),
            Endpoints = new List<OpenHEndpointConfiguration>(){
                new OpenEndpointConfiguration {
                    Reference = "test", ServiceUrl = "test", DatabaseKey = 1, EnableMessageLogging = true
                } },
            Views = new List<OpenViewConfiguration>(),
            Entities = new List<OpenEntityConfiguration>()
        };
        var mockOServiceContext = new Mock<OServiceContext>(mockOServiceConfig);
        var mockOpenDbContext = new Mock<OpenDbContext>();
        var mockOpenDbSet = new Mock<DbSet<Member>>();

        mockOpenDbSet.Setup(s => s.Find(It.IsAny<int>())).Returns(new Member());
        mockOpenDbContext.Setup(s => s.Set<Member>()).Returns(mockOpenDbSet.Object);

        //Act
        var memberRepository = new MemberRepository(mockOServiceContext.Object, mockOpenDbContext.Object);
        var member = memberRepository.GetMember(1, 1);

        //Assert
        Assert.NotNull(member);
        Assert.IsAssignableFrom<Member>(member);
    } 
}

这出错了-

System.NullReferenceException:“对象引用未设置为对象的实例。”配置为空。

基本上,参数在发送给AuthenticationService时对于配置无效。但是我的问题不是真的关于解决错误。尝试为所有这些服务传递正确的模拟参数真的是最好的方法吗?当我要实际测试的只是一个相对琐碎的Get方法时,肯定有更好的方法来模拟这一点?

我也知道,根据您对模拟服务和数据的处理方式,单元测试可以转变为集成测试。我只想听听任何处理过类似问题的人的想法。老实说,这是我第一次尝试对存储库进行单元测试,而在尝试尽可能多地使用该主题的同时,我也非常感谢任何指导。

0 个答案:

没有答案