Как обрабатывать исключение thrown в NUnit

Я написал класс модульного теста на C# для моего проекта MVC.

метод испытания следующий

 [Test]
    public void To_Add_DocumentStatusIsNull_ThrowsInvalidOperationException_ServiceTest()
    {
        try
        {

        _IDocumentStatusRepositoryMock = new Mock<IDocumentStatusRepository>();
        _unitOfWorkMock = new Mock<IUnitOfWork>();

        DocumentStatusService documentStatusService = new  
         DocumentStatusService(_unitOfWorkMock.Object,  
          _IDocumentStatusRepositoryMock.Object); 

        DocumentStatus documentStatus;
        documentStatus = null;

        _IDocumentStatusRepositoryMock.Setup(m => m.Add(documentStatus));
        documentStatusService.Add(documentStatus);

        Assert.Pass();

        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
    }

и метод обслуживания следующий

   public virtual void Add(TEntity entity)
    {
        try
        {

        if (entity == null)
        {
            throw new ArgumentNullException("entity");
        }
        _repository.Add(entity);

        }
        catch (Exception e)
        {
            throw new Exception(e.Message);
        }
    }

теперь этот метод теста только не прошел из-за класса службы, вызванного ArgumentNullException.Итак,как обрабатывать ArgumentNullException или как сделать этот тест?

пожалуйста, кто-нибудь помогите

3 ответов


Если вы пытаетесь проверить, что ArgumentNullException работает (что не в настоящее время). тогда это звучит, как вы хотите:

[Test, ExpectedException(typeof(ArgumentNullException), ExpectedMessage = @"Value cannot be null.
Parameter name: entity")]
public void To_Add_DocumentStatusIsNull_ThrowsInvalidOperationException_ServiceTest()
{
    _IDocumentStatusRepositoryMock = new Mock<IDocumentStatusRepository>();
    _unitOfWorkMock = new Mock<IUnitOfWork>();

    DocumentStatusService documentStatusService = new  
     DocumentStatusService(_unitOfWorkMock.Object,  
      _IDocumentStatusRepositoryMock.Object); 

    DocumentStatus documentStatus;
    documentStatus = null;

    _IDocumentStatusRepositoryMock.Setup(m => m.Add(documentStatus));
    documentStatusService.Add(documentStatus);
}

...

public virtual void Add(TEntity entity)
{
    if (entity == null)
    {
        throw new ArgumentNullException("entity");
    }
    _repository.Add(entity);
}

Я предполагаю: глядя на код, этот модульный тест не должен проходить. Добавление NULL в список в большинстве случаев не является намеренным поведением.

Я вижу 2 варианта: A)вы должны добавить try / catch к тестовому методу.

try 
{
    _IDocumentStatusRepositoryMock.Setup(m => m.Add(documentStatus));
    documentStatusService.Add(documentStatus);
}
catch (Exception )
{
    Assert.Fail(); // or nothing is expected behaviour
}

B) удалите блок try/catch из метода тестирования, чтобы не проглотить исключение. (Каждый тест, который не терпит неудачу или Assert или thows необработанное исключение автоматически проходит)


тестирование для ArgumentNullException

если вы удалите неблагоразумно

catch (Exception e)
{
   throw new Exception(e.Message);
}

из вашего кода для тестирования (текущий catch теряет контекст ошибки и разрывает трассировку стека, см. ниже), ваш тест может быть таким же простым, как упаковка вызова в Assert.Throws<ArgumentNullException>():

[Test]
public void PassingANullEntityToAddMustThrowArgumentNullException()
{
    var documentStatusService = new  DocumentStatusService(...); 
    Assert.Throws<ArgumentNullException>(() =>  documentStatusService.Add(null));
}

Re: Ваш Обработчик Исключений

в вашем сервисном коде никогда не ловите исключение и не перестраивайте его, как вы сделано, так как это потеряет трассировку стека (например,_repository.Add(entity); может бросить, а также.). Вы также не добавляете никакого значения, бросая e.Message поскольку это уже в исходном исключении (с дополнительной информацией, такой как трассировка стека и внутреннее исключение)

плохое:

  catch (Exception e)
  {
      throw new Exception(e.Message);
  }

лучше: если вы поймаете и перестроите с некоторым значением, оберните оригинал как внутреннее исключение:

 catch (SqlException ex)
 {
    throw new Exception("Some value add here", ex);
 }

или если вы просто перехватываете и позволяете распространять:

 catch (SqlException)
 {
    // Do some logging
    throw;
 }

лучшие для меня было бы позволить исключению распространяться, если вы либо добавляете значение, либо обрабатываете его.