jokul
jokul

Reputation: 1339

I want to assert that an exception was thrown within a certain class

I am building a TestProject for my client/server setup. I want to verify that a test fails within a certain block of execution (there is no client to send to so the server's Send() method will throw an exception). Since I do not want to have the tests boot up a client and server and have them communicate (which I have had problems doing on a single machine.)

If the code reaches this line, that means that the program's execution flow could only fail within the responsibilities of another test. Is there an easier way to do this other than doing a substring check on the thrown exception's stacktrace? I feel like this method is not very expandable and would require constant attention if class names change.

Is there a way that doesn't even involve manually checking the exception's stacktrace?

Upvotes: 0

Views: 1516

Answers (3)

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236328

When you are unit-testing some class, there is two sources of exception:

  1. Class which you are testing can throw an exception
  2. Dependency of a class can throw an exception

In second case you usually either handle exception, or wrap it in more high-level exception and throw it to caller. So, how to test all these cases?

System under test throws exception

E.g. throwing exception in case of wrong argument passed to method (NUnit sample):

StockService service = new StockService();
Assert.Throws<ArgumentNullException>(() => service.Connect(null));

You don't need to check stack trace, because it's a class under test who supposed to throw exception.

Dependency throws exception and we handle it

When your class has dependencies, you should mock dependencies in order to test your class in isolation. So, it's very easy to setup mocks to throw exceptions when your class interacts with them. Consider case when service should run on default settings if configuration file not found (Moq sample):

var configMock = new Mock<IStockServiceConfig>();
configMock.Setup(c => c.Load()).Throws<FileNotFoundException>();

StockService service = new StockService(configMock.Object);
service.Connect("google");

configMock.VerifyAll();
Assert.That(service.Port, Is.EqualTo(80));

This test will fail if you will not try to load config, or if you will not handle FileNotFoundException.

Exception stacktrace does not matters here - we don't care whether our direct dependency thrown exception, or it was some other class inside dependency. Actually we don't know if that class exists - we are interacting only with direct dependency. And we should care only about fact that dependency can throw exception, which we can handle.

Dependency throws exception and we wrap it

And last case - wrapping exception in something more high-level. Consider previous sample, but config is really important and you can't start without configuration file. In this case you wrap FileNotFoundException into something more business-specific, which makes sense at higher levels of your application. E.g. StockServiceInitializationException:

var configMock = new Mock<IStockServiceConfig>();
configMock.Setup(c => c.Load()).Throws<FileNotFoundException>();

StockService service = new StockService(configMock.Object);
Assert.Throws<StockServiceInitializationException>(_ => service.Connect("bing"));

configMock.VerifyAll();

As you can see, we also don't care about stacktrace of exception, which throws our dependency. It also could be some wrapper of more low level exception. Expected behavior of service - throw high-level initialization exception if config not found. We are verifying that behavior here.

Upvotes: 0

Atrov
Atrov

Reputation: 23

Is there anything unique about the exception in the class, other than that it's specific to that class?

If it's identifiable by the message you can test it as the other answer has shown, or like this if you're not using NUnit:

try {    
   myMethod();
   Assert.Fail("Expected exception to be thrown."); 

} catch (MyException ex) {    
   Assert.Equals("My Exception Message", ex.Message, "Exception message was formatted incorrectly.");

} catch (Exception) {    
   Assert.Fail("An exception was thrown, but of the wrong type.");    
}

Upvotes: 0

Mechanical Object
Mechanical Object

Reputation: 666

If you are using NUnit

Without using DataAnnotations

[Test]
public void Test_XXXXXXX
{
    var yourClass = new YourClass(); 
    Assert.That(()=>yourClass.Method(),
                    .Throws.Exception
                    .TypeOf<TypeOfYourException>
                    .With.Property("Message")
                    .EqualTo("the message you are expecting goes here")
               );
}

Using DataAnnotations

[Test]
[ExpectedException(typeof(ExceptionType), ExpectedMessage="your message goes here!")]
public void Test_XXXXXXX
{
      var yourClass = new YourClass();     
      // Call your method in a way that it will fail
      yourClass.YourMethod();
}

Upvotes: 2

Related Questions