AOP frameworks normally address cross-cutting concerns. Exception handling is one of them. I may say that I want to log invocation of every method in my business layer and I also want to intercept and log every exception thrown by any method in that business layer.
When it comes to unit testing, I don't want to test that aspect oriented framework intercepts the method call and logs the exception. People who wrote the aspect oriented framework did this testing already and they know that it works.
What you probably want to test is how the code behaves when the exception is thrown. You normally achieve this with mocking frameworks. For example, in my business layer I have a method that returns me latest films:
[LogExceptionThroughAOPFramework]
public IEnumerable<FilmSummary> GetLatestFilms()
{
var latestFilms = _repository.GetLatestFilms();
var latestFilmsDTO = Mapper.Map<FilmSummaryDTO>(latestFilms);
return latestFilmsDTO;
}
Now, above method may fail when it calls _repository.GetLatestFilms();
There is also an imaginary attribute called LogExceptionThroughAOPFramework
- it intercepts a method call and logs the exception.
When it comes to testing this method, you don't want to check that AOP framework logs the exception. It's a third party dependency and you don't want to rely on that dependency. Interception has already been tested by people who wrote the framework. If all your exception handling/logging is done by AOP framework, then you don't need to test it. Instead, test logic of LogExceptionThroughAOPFramework
and that should be enough.
If you don't use AOP framework, then use a mocking framework. For example:
[TestMethod]
[ExpectedException(typeof(RelevantTypeOfException)]
public void GetLatestFilms_RepositoryThrowsException_ExpectExceptionToBePropagated
{
var repository = new Mock<ILatestFilmsRepository>();
repository.Expect(call => call.GetLatestFilms()).Throws(new RelevantTypeOfException());
var client = new FilmClient(repository);
// Throws exception
client.GetLatestFilms();
}
In above test I say that I expect exception to be thrown (attribute above test method). I then configure my repository (mock) to throw an exception when I try to get latest films. Finally, I make a client object and attempt to get a list of latest films. In the constructor I pass a mock repository, which then throws an exception. The test will pass as the exception will be thrown.
Also, you said:
With AOP I can create an aspect that will throw an expected exception
and attach it to the method called before exception handling.
If you do that, then what will you be testing? If exception is thrown by aspect, then you won't be testing your business logic. You will be testing aspect throwing exceptions. I don't see any value in that.
Update
You could potentially add an aspect to whatever it is that you are testing.
You would have to add an aspect for each test. Your aspect must be aware of the context its being executed in, i.e. it needs to know that code is executing in a test context.
So if I wanted to test how the system behaves if repository throws an exception, I'd have to write something on the lines of:
[ThrowExceptionOnlyDuringTest("TestScenario")]
[ThrowExceptionOnlyDuringTest("DifferentTestScenario")]
public IEnumerable<FilmSummary> GetLatestFilms()
{
// Logic to retrieve films
}
I don't know how you would then wire up your test to this aspect. As far as I can see it, this is not much different to setting expectations on mocks. Aspect will create a proxy for method execution and will throw an exception. Mocking framework will do exactly the same, but in a simpler way.
Update 2
I'm assuming that in your case, you are testing integration of the entire system. You have access to all the components and you are trying to find a nice way of making these components fail during integration tests. AOP approach might work here, I'm still not sure.
What happens in the scenario where you don't have control over components that you are integrating with? For example, if your system talks to currency exchange service in another country, there will be no way you'll get it to fail. In this instance you will simply mock this service and make it throw an exception during integration testing. Because of this, I think it makes sense to have an integration tests with a mock that throws an exception in certain scenario.