AutoFixture相关对象属性

时间:2016-05-17 10:34:15

标签: c# unit-testing autofixture

我正在编写一些单元测试,并且遇到了一段感觉像代码味道的代码。

基本上我有一个Web Api。它收到一个传入的请求' SomeRequest':

public class SomeRequest
{
    public string Name { get; set; }
    public IEnumerable<int> RequestedDataIds { get; set; } 
}

作为我测试的一部分。我需要确保所有这些&#39; RequestedDataIds&#39;是有效的。我有一个方法调用系统的另一部分,它返回一个有效的&#39; SomeData&#39;对象。 &#39; SomeData&#39;对象包含要验证的ID:

public class SomeData
{
    public int Id { get; set; } //Id to validate against
    public string Name { get; set; }
}

我正在测试的系统看起来像这样:

    public void Execute(RequestA request)
    {
        var validDataIds = _someService.GetValidEntities().Select(x => x.Id).ToList();

        var invalidRequestIds = request.RequestedDataIds.Where(requestedId => !validDataIds.Contains(requestedId));

        if (invalidRequestIds.Any())
        {
            throw new SomeException("Error");
        }

        //Carry on as normal
    }

我的问题是。是否有最佳实践或任何方式让AutoFixture让这两个集合相互交互,以便我可以进行测试:

  1. 测试在具有无效请求ID
  2. 的情况下引发异常
  3. 让所有其他测试确保它们是相同的,因此不会抛出异常
  4. AutoFixture是否应该用于此场景?我可以提取逻辑并使其成为类的新依赖项。不得不只测试它。但是,测试依赖类本身仍然会引发问题1&amp; 2。
  5. 这是我目前对这个问题的尝试。我只是不喜欢它。

    1 - 确保不同的id引发异常

        [Test]
        public void Test1()
        {
            _fixture = new Fixture();
    
            var request = _fixture.Create<SomeRequest>();
            var dataEnitities = _fixture.CreateMany<SomeData>();
    
            var maxDataEntityId = dataEnitities.Select(x => x.Id).Max();
    
            request.RequestedDataIds = new List<int> {maxDataEntityId + 1};
    
            _someService.GetValidEntities.Returns(dataEnitities);
    
            //Ensure exception is thrown
        } 
    

    2 - 确保相同的ID以防止异常

        [Test]
        public void Test1()
        {
            _fixture = new Fixture();
    
            var request = _fixture.Create<SomeRequest>();
            var dataEnitities = _fixture.CreateMany<SomeData>();
    
            request.RequestedDataIds = dataEnitities.Select(x => x.Id);
    
            _someService.GetValidEntities.Returns(dataEnitities);
    
            //Ensure no exception is thrown
        }  
    

    注意 - 此代码大大减少了实际实现。因此,请不要关心它的外观和实施方式。

1 个答案:

答案 0 :(得分:1)

是的,这是代码味道。您的测试是有效的,但它们可能很简单。 AutoFixture是一个很好的工具,但在这种特殊情况下,我认为你不需要它。

首先,尝试尽可能简化Execute()方法。它或多或少地在Presentation / Controller / Api层中使用,因此尽可能保持精简。不要任何胖控制器。

你真的只需要调用服务方法。

    public void Execute(RequestA  request)
    {
        _someService.ValidateEntities(request);
    }

注意方法名称。它没有返回任何东西。 您的服务可以是:

    public interface ISomeService
    {
        void ValidateEntities(RequestA request);
    }

此实现将从基础数据源或服务返回ValidDataEntities。

    var validDataIds = GetValidEntities().Select(x => x.Id);

我假设您从某种存储库或其他服务获取实体列表。

将您的逻辑推送到更多域/ poco对象。

创建一个简单的POCO类,即EntityValidator,它接受您的Request和validDataIds。 你可以单独测试这个POCO类,而不必使用AutoFixture或任何模拟。

public class EntityValidator
{
    public void Validate(IEnumerable<int> validEntityIds, RequestA request)
    {
        var invalidRequestIds = request.RequestedDataIds.Where(requestedId => !validEntityIds.Contains(requestedId));

        if (invalidRequestIds.Any())
        {
            throw new SomeException("Error");
        }
    }
}

您的单元测试很简单,您可以使用测试框架方法,即NUnit中的.Thorws测试异常情况。