如何正确测试.net服务逻辑

时间:2018-08-07 15:07:28

标签: c# testing

我有一个运行正常的测试,但我需要有关如何正确测试逻辑的指导。我对测试的理解是,应该在不与资源紧密耦合的情况下完成测试(这是进行模拟的地方),但是如果所有内容都经过模拟(尤其是返回结果),那么如何在不实例化一堆类的情况下正确地测试逻辑?

ValidateEmployeeConfigurationAsync(如下)将返回RulesValidationResult,这是我要声明的内容。因此,我可以回答我自己的问题,即如何更新存储库和服务-这是一种方法。是否有最佳实践来实现这一目标?感觉不对。

功能测试

  [TestMethod]
  public async Task PassValidateEmployeeConfigurationTest()
  {
        //ARRANGE
        const long employeeId = 200L;
        const int configurationTypeId = (int) Constants.Configuration.ConfigurationTypes.User;
        const bool enabled = true;

        _ruleService = new Mock<IRuleService>();
        _configurationService = new Mock<IConfigurationService>();          
        _ruleFacade = new Mock<IRuleFacade>();

        _configurationService.Setup(x => x.GetByConfigurationNameAsync(It.IsAny<string>()))
            .ReturnsAsync(GetConfigurations(enabled));

        _ruleService.Setup(x => x.GetConfigRulesByEmployeeIdAsync(It.IsAny<long>()))
            .ReturnsAsync(GetRules(enabled));

        _ruleFacade.Setup(x =>
                x.ValidateEmployeeConfigurationAsync(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<int>()))
            .ReturnsAsync(GetPassedValidationResult());

        //ACT
        var result = await
            _ruleFacade.Object.ValidateEmployeeConfigurationAsync(employeeId, "TestConfiguration", configurationTypeId);

        //ASSERT
        Assert.IsNotNull(result);
        Assert.AreEqual(true, result.PassedValidation);
  }

感兴趣的方法

  public async Task<RulesValidationResult> ValidateEmployeeConfigurationAsync(long employeeId, string configurationName, int configurationTypeId = 6)
  {
        var key = GetDefaultKey(configurationName);
        var rules = new List<Rule>();
        var validationResult = new RulesValidationResult();
        validationResult.Messages.Add("Configuartion not found", configurationName);

        var configurations = await _configurationService.GetByConfigurationNameAsync(configurationName);

        if (!configurations.Any())
            return validationResult;

        var configuration = configurations.FirstOrDefault(c => c.ConfigurationTypeId == configurationTypeId);
        rules = await _ruleService.GetConfigRulesByEmployeeIdAsync(employeeId);

        if (rules.Any() && configuration.ConfigurationSettings.Any())
        {
            var testTargets = new List<ConfigurationSetting>();
            testTargets.AddRange(from setting in configuration.ConfigurationSettings
                where setting.IsActive && setting.Key == key
                select new ConfigurationSetting
                {
                    ConfigurationId = setting.ConfigurationId,
                    Key = setting.Key,
                    Value = setting.Value
                });

            if (PassesRules(testTargets, rules))
            {
                var msg = $"{configurationName} passed rule validation";
                validationResult.PassedValidation = true;
                validationResult.Messages.Clear();
                validationResult.Messages.Add("Passed", msg);
            }
            else
            {
                var msg = $"{configurationName} failed rule validation";
                validationResult.Messages.Clear();
                validationResult.Messages.Add("Failed", msg);
            }
        }

        return validationResult;

  }

1 个答案:

答案 0 :(得分:0)

这就是我构建测试的方式,查看TestMethod的先前版本以查看差异。在最初的问题中,如果测试的结构方式不正确,则测试将始终通过。

在此版本中,模拟了输入,模拟了依赖项,并设置了IOC容器,以便测试目标代码并将断言应用于生成的输出。

  [TestMethod]
  public async Task PassValidateEmployeeConfigurationTest()
  {
        //ARRANGE
        const long employeeId = 200L;
        const int configurationTypeId = (int) Constants.Configuration.ConfigurationTypes.User;
        //need the IOC container 
        var unityContainer = new UnityContainer();

        //Mock ALL the dependencies (services and repositories)
        var ruleFacade = new Mock<IRuleFacade>();
        var employeeConfigMapRepo = new Mock<IEmployeeConfigurationMapRepo>();
        var ruleRepo = new Mock<IRuleRepo>();
        var ruleService = new Mock<IRuleService>();
        var configurationService = new Mock<IConfigurationService>();
        var employeeConfigurationService = new Mock<IEmployeeConfigurationService>();
        var organizationConfigurationService = new Mock<IOrganizationConfigurationService>();
        var facilityConfigurationService = new Mock<IFacilityConfigurationService>();
        var configurationSettingService = new Mock<IConfigurationSettingService>();

        // configure the dependencies so that the proper inputs are available
        configurationService.Setup(x => x.GetByConfigurationNameAsync(It.IsAny<string>()))
            .ReturnsAsync(GetConfigurations(true));

        employeeConfigMapRepo.Setup(x => x.GetAllByEmployeeIdAsync(It.IsAny<int>()))
            .ReturnsAsync(GetEmployeeConfigMaps(true));

        employeeConfigurationService.Setup(x => x.GetAllByEmployeeIdAsync(It.IsAny<long>()))
            .ReturnsAsync(GetEmployeeConfigMaps(true));

        ruleRepo.Setup(x => x.GetByConfigurationIdAsync(It.IsAny<int>()))
            .ReturnsAsync(GetRules(true));

        ruleService.Setup(x => x.GetConfigRulesByEmployeeIdAsync(It.IsAny<long>(), It.IsAny<string>()))
            .ReturnsAsync(GetRules(true));

        // help the IOC do its thing, map interfaces to Mocked objects
        unityContainer.RegisterInstance<IRuleService>(ruleService.Object);
        unityContainer.RegisterInstance<IRuleRepo>(ruleRepo.Object);
        unityContainer.RegisterInstance<IConfigurationService>(configurationService.Object);
        unityContainer.RegisterInstance<IEmployeeConfigurationService>(employeeConfigurationService.Object);
        unityContainer.RegisterInstance<IOrganizationConfigurationService>(organizationConfigurationService.Object);
        unityContainer.RegisterInstance<IFacilityConfigurationService>(facilityConfigurationService.Object);
        unityContainer.RegisterInstance<IConfigurationSettingService>(configurationSettingService.Object);
        unityContainer.RegisterInstance<IRuleFacade>(ruleFacade.Object);

        // thanks to all the mocking, the facade method ValidateEmployeeConfigurationAsync can now be tested properly
        var ruleHelper = unityContainer.Resolve<RuleFacade>();

        //ACT
        var result = await
            ruleHelper.ValidateEmployeeConfigurationAsync(employeeId, _testConfigName, configurationTypeId);

        //ASSERT
        Assert.IsNotNull(result);
        Assert.AreEqual(true, result.PassedValidation);
    }