Утверждение исключений для частных методов

Я тестирую юнит-тесты в C# с помощью NUnit.

Например, мой метод (если публичный) ArgumentNullException, Я могу утверждать, что метод бросает ArgumentNullException вот так: Assert.Throws<ArgumentNullException>(() => method.Call());

Однако, так как я вызываю приватный метод с использованием отражения, я бы утверждал TargetInvocationException за метод, который бросает ArgumentNullException вот так: Assert.Throws<TargetInvocationException>(() => methodInfo.Invoke(obj, new object[] { params }));

Я хотел бы заявить ArgumentNullException вместо TargetInvocationException для этого частного метода, чтобы я мог просмотреть его код и узнать, что он должен делать, а не отлаживать, чтобы выяснить.

Как бы я утверждал для фактического исключения, а не TargetInvocationException?

ПРИМЕЧАНИЕ. Этот вопрос не затрагивает теорию, лежащую в основе открытых и закрытых методов модульного тестирования. Моя команда и я приняли решение провести юнит-тестирование закрытых методов, и вопрос о том, является ли это способом юнит-тестирования, не имеет отношения к этому вопросу. Посмотрите ответ на этот вопрос с наибольшим количеством голосов, чтобы понять наше обоснование.

3 ответа

Решение

Нашел мой ответ:

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

ОБНОВИТЬ

Assert.IsNotNull(exception.InnerException) дайте мне знать, что существует внутреннее исключение. Assert.IsInstanceOf<Exception>(exception.InnerException); будет утверждать любой тип Exception выброшены. Я согласен, что оба способа говорят нам, что есть внутреннее исключение.

Однако..... что, если я хочу утверждать для определенного типа внутреннего исключения?

Например, если мой метод выдает ArgumentNullExceptionто я не могу утверждать это, делая Assert.IsInstanceOf<FileNotFoundException>(exception.InnerException); С помощью Assert.IsNotNull позволяет мне знать, что существует внутреннее исключение, но оно не раскрывает тип внутреннего исключения. Поэтому я предпочитаю использовать IsInstanceOf в этом случае.

Создайте метод расширения в Assert, то есть "ThrowsInnerException", который принимает функцию, оберните с помощью Try/Catch и выбросите InnerException (который, в вашем случае, соответствует ArgumentNullException)

Вот фрагмент кода (непротестирован и не компилируется, так как я набрал его без редактора, но он должен дать вам идею)

public static class AssertExtension 
    {
        public static void ThrowsInnerException<T>(Action action) 
        {
            Assert.Throws<T>(delegate() {
                try { action(); }
                catch (Exception exc) { throw exc.InnerException; }
            });
        }
    }

Вы уверены, что частные методы юнит-тестирования - это хорошая идея? Потому что звучит так, будто это не так.

Лучше протестировать открытый метод, который вызывает закрытый метод.

Обновить

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

Update2
Нашел довольно похожий ТАК вопрос

Update3
Подход, который я использовал в аналогичном случае(для насмешек private поля) было просто отметить private методы как internal и добавить InternalsVisibleTo(<assembly_with_unit_tests>) атрибут для тестируемой сборки.
Это не очень хорошая идея (на самом деле я был против этого, когда это было предложено в команде на одной из сессий разработки, потому что это не правильно, не чисто и т. Д.), Но в результате это сэкономило много времени для написания юнит-тестов.

Другие вопросы по тегам