5

I am unit-testing private methods in C# using NUnit.

For example, my method (if public) is expected to throw an ArgumentNullException. I can assert that the method throws an ArgumentNullException like so: Assert.Throws<ArgumentNullException>(() => method.Call());

However, since I am invoking a private method using reflection, I would assert a TargetInvocationException for the method that throws an ArgumentNullException like so: Assert.Throws<TargetInvocationException>(() => methodInfo.Invoke(obj, new object[] { params }));

I would like to assert an ArgumentNullException instead of a TargetInvocationException for that private method so I can scan over its code and know what its expected to do rather than to debug to find out.

How would I assert for the actual exception, instead of a TargetInvocationException?

NOTE: This question is not addressing the theory behind unit-testing public vs. private methods. My team and I have made the decision to unit-test the private methods, and whether or not that is the way to unit-test is irrelevant to this question. See the most upvoted answer on this question to understand our rationale.

Community
  • 1
  • 1

3 Answers3

8

Found my answer:

var exception = Assert.Throws<TargetInvocationException>(() => methodInfo.Invoke(obj, new object[] { params }));
Assert.IsInstanceOf<Exception>(exception.InnerException);

UPDATE

Assert.IsNotNull(exception.InnerException) lets me know that an inner exception exists. Assert.IsInstanceOf<Exception>(exception.InnerException); will assert any type of Exception thrown. I agree that both ways tell us that there is an inner exception.

However.....what if I want to assert for a specific type of inner exception?

For example, if my method throws an ArgumentNullException, then I cannot assert for that by doing Assert.IsInstanceOf<FileNotFoundException>(exception.InnerException); Using Assert.IsNotNull lets me know that an inner exception exists, but it does not reveal the type of the inner exception. Therefore, this is why I prefer using IsInstanceOf in this case.

3

Make an extension method on Assert, i.e "ThrowsInnerException" that take a func, wrap with a Try/Catch and throw the InnerException (which, in your case, correspond to the ArgumentNullException)

Here is a piece of code (untested & doesn't compile, as I typed it without editor, but it should give you the idea)

public static class AssertExtension 
    {
        public static void ThrowsInnerException<T>(Action action) 
        {
            Assert.Throws<T>(delegate() {
                try { action(); }
                catch (Exception exc) { throw exc.InnerException; }
            });
        }
    }
Fabske
  • 2,106
  • 18
  • 33
0

Are you sure that unit-testing private methods is good idea? Because sounds like it isn't.

It's better to test public method that is calling private method.

Update

What's more, despite I didn't see your code, but I think it's better to put parameters validation to public methods and test them.

Update2
Found pretty similar SO question

Update3
Approach that I was using in similar case(for mocking private fields) was just to mark private methods as internal and to add InternalsVisibleTo(<assembly_with_unit_tests>) attribute to assembly under test.
It's not good idea(actually I was against this when it was proposed in team on one of design session, because it's not right, not pure, etc), but as the result it saved a lot of time for writing unit-tests.

Community
  • 1
  • 1
alex.b
  • 4,547
  • 1
  • 31
  • 52
  • The public method that calls these private methods have been tested. As I stated above, my team has determined to test the private methods as there are many parts within the public method. –  May 15 '12 at 15:21
  • 1
    See [this](http://stackoverflow.com/questions/1506427/unit-testing-private-code). The most upvoted answer explains our rationale in taking this route. –  May 15 '12 at 15:25
  • Testing the public method necesarily means you have tested the private methods. They are not distinct. – Tejs May 15 '12 at 15:31