Утверждение исключений для частных методов
Я тестирую юнит-тесты в 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>)
атрибут для тестируемой сборки.
Это не очень хорошая идея (на самом деле я был против этого, когда это было предложено в команде на одной из сессий разработки, потому что это не правильно, не чисто и т. Д.), Но в результате это сэкономило много времени для написания юнит-тестов.