Как тестировать private и protected методы? [дубликат]

237
19 июля 2017, 21:05

На данный вопрос уже ответили:

  • Как тестрировать private и protected методы? 4 ответа

У меня есть класс:

public abstract class SomeClass {
    private readonly ISomeInterface _interface;
    protected SomeClass(ISomeInterface interface) {
        this._interface = interface;
    }
    protected virtual void SomeMethod(string someProp) {
        if (_interface == null) throw new ArgumentNullException();
        if (String.IsNullOrEmpty(someProp)) throw new ArgumentNullException();
    }
}

Пытаюсь написать тест, который проверяет будут ли вылетать Exception при разных условиях (на каждый exception свой метод теста). Как вызывать методы я, вроде, понял:

[TestMethod]
public void SomeClass_WhenISomeInterfaceIsNull_ShouldThrowArgumentNullException
{
   var someClassMock = new Mock<SomeClass>(null);
   var result = site.Protected().Setup<string>("SomeMethod", "1111");
}

Метод, вроде, вызван, но как проверить было ли в нем выброшено исключение?

PS:Ответ предложенный sp7, здесь не походит. Мой ISomeInterface работает с сетью. Возвращаемый им результат, для данного приложения не походит, например, он возвращает json строку, а конечному классу(наследнику SomeClass) нежен он в виде класса. Реализовывать преобразование из Json в class в ISomeInterface нет смысла, так как:

  1. Может потянуться за собой не нужные зависимости(например, Newtonsoft.Json)
  2. Будет использоваться в других приложениях, где может быть уже не Json.

Использовать дополнительный класс, в который будет инжектиться ISomeInterface, который в свою очередь будет инжектиться в наследников SomeClass, тоже плохой вариант так как:

  1. В методе SomeMethod класса SomeClass выполняются действия зависящие от настроек наследников. Например, количество запросов, которое
    должно быть совершено если не поступил ответ или другим причинам.
  2. Выносить настройки SomeClass в ISomeInterface не правильно, так как это приведет к множеству проинициализированных классов реализующих ISomeInterface (что является недопустимым), либо к добавлению сохранения настроек в реализации ISomeInterface (что тоже является недопустимым, так как это не его задача).
Answer 1

Есть рассматривать тот код, который представлен в примере, то для тестов вы просто можете создать еще один класс для тестирования, который будет наследовать SomeClass и открывать нужные вам protected члены класса. Не вижу криминала в подобном подходе.

public SomeClassNew : SomeClass {
  public SomeClassNew(ISomeInterface interface) : base(interface)
  public void SomeMethodTest(string someProp) {
    base.SomeMethod(someProp);
  }
}

Но лучше сделать конструктор для класса открытым.

Для вызова private методов класса вы можете использовать рефлексию:

SomeClass someClass = new SomeClass(someInterface);
MethodInfo methodInfo = typeof(SomeClass).GetMethod("SomeMethod", 
    BindingFlags.NonPublic | BindingFlags.Instance);
methodInfo.Invoke(someClass, new object[] { someProp });

"Правильность" данного подхода каждый для себя определяет сам, я не вижу в этом ничего дурного. По крайней мере для тестирования.

READ ALSO
Реализация класса c#

Реализация класса c#

Имеется 3 формы, на каждой по Chart

195
Цикличный буфер в фоновом потоке

Цикличный буфер в фоновом потоке

Имеется цикличный буфер, который непрерывно заполняется в фоновом потокеМне необходимо раз в секунду считывать его и обновлять UI интерфейс

196
StrongTypingException при создании модели из Базы Данных

StrongTypingException при создании модели из Базы Данных

Продолжаю мучать EntityСоздаю модель MySQL БД

265
TLSharp exception во время чтения сообщений

TLSharp exception во время чтения сообщений

Я читаю сообщения из чата используя следующий код:

494