简体   繁体   中英

How to handle thrown exception in NUnit

I have written a unit test class in C# for my MVC project.

The Test Method is following

 [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);
        }
    }

And the Service Method is following

   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);
        }
    }

Now This test method only not passed due to the service class thrown ArgumentNullException.So how to handle the ArgumentNullException or How to make this test pass?

Please anybody help

If you are trying to check that the ArgumentNullException is working (which: it isn't currently). then it sounds like you want:

[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);
}

I am assuming: Looking at the code this unit test should not pass. Adding a NULL to a list is in most cases not an intended behaviour.

I see 2 options: A) You should add a try/catch to you Test metod.

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

B) Remove the try/catch block from the Test Method so you do not swallow the exception. (Every Test that does not fails or an Assert or thows an unhandeled exception automatically passes)

Testing for the ArgumentNullException

If you remove the ill-advised

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

from your code to be tested (The current catch loses context of the error, and breaks the stack trace, see below), your test can be as simple as wrapping the invocation in an Assert.Throws<ArgumentNullException>() :

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

Re: Your Exception Handler

In your service code, never catch an exception and rethrow it as you've done, as this will lose the stack trace (eg _repository.Add(entity); could throw as well.). You also aren't adding any value by throwing e.Message as this is already in the original exception (with additional info like stack trace and inner exception)

Bad:

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

Better: If you do catch and rethrow with some value, wrap the original as an inner exception:

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

or if you are just intercepting and allow to propagate:

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

Best to me would to let the exception propagate, unless you either adding value, or handling it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM