2014-10-19 2 views
0

Например, у меня есть следующий метод:Правильная работа с исключениями

 public void MeetingNoteSave(int MeetingID, string note, bool IsInviter, string Username) 
     { 
       meeting = Get<Meeting>(p => p.MeetingID == MeetingID && p.UserInviter.aspnet_User.UserName == Username); 
       MeetingNoteSaveCheckings(meeting, MeetingID); 
// some actions here 
     } 

     void MeetingNoteSaveCheckings(Meeting meeting, int MeetingID) 
     { 
      DateTime currentDateWithTime = DateTime.Now; 
      if (meeting == null) 
      { 
       throw new Exception("Meeting does not exist. MeetingID=" + MeetingID); 
      } 
      DateTime meetingTime = meeting.MeetingTime.Day.AddHours(meeting.MeetingTime.Hour).AddMinutes(meeting.MeetingTime.Minute); 
      if (meetingTime > currentDateWithTime) 
      { 
       throw new Exception("Meeting is future. MeetingID=" + MeetingID + ". Meeting time = '" + meetingTime + "', Current time='" + currentDateWithTime + "'"); 
      } 
     } 

так, метод может бросить 2 исключения - при встрече не существует с такими параметрами на всех или когда время встречи более чем текущее время (должен быть прошлым или текущим).

Теперь, я пишу Unit Tests. Простой метод:

[TestMethod] 
    public void MeetingNoteSave() 
    { 
     _repository.MeetingNoteSave(1, "My note", true, "[email protected]"); 
    } 

Разумеется, тест модуля вызова будет терпеть неудачу с некоторыми параметрами. Я хочу поймать эти случаи, поэтому тест должен быть успешным. Я могу сделать двумя способами. Во-первое это просто, но немного грязный:

 try 
     { 
      _repository.MeetingNoteSave(1, "My note", true, "[email protected]"); 
     } 
     catch(Exception ex) 
     { 
      if (ex.Message.IndexOf("Meeting does not exist")>=0) 
      { 
       // some actions 
      } 

      if (ex.Message.IndexOf("Meeting is future")>=0) 
      { 
       // some actions 
      } 
     } 

так, тест будет успешный с неверными параметрами ввода (так, блок тест может быть использован для проверки методы с неправильными параметрами), но не с встречающимися ошибками. Хорошо.

Другой способ - создать специальные исключения фиктивных как MeetingNullException и MeetingFutureException

public class MeetingNullException : Exception 
{ 
} 

public class MeetingFutureException : Exception 
{ 
} 

бросить их и поймать их. Вернее, но гораздо больше кода. Манекен-код. Какой путь вернее?

ответ

3

Они оба ошибаются. Ваш второй подход находится в правильном направлении: вам следует избегать бросать общие исключения типа Exception; конкретные подклассы гораздо более выразительны.

То, что вы должны сделать в ваших тестах, то есть использовать атрибут [ExpectedException], который заставит их выглядеть следующим образом:

[TestMethod] 
[ExpectedException(typeof(MeetingNullException))] 
public void MeetingNoteSave_WithNotExistingMeeting() 
{ 
    _repository.MeetingNoteSave(1, "My note", true, "[email protected]"); 
} 

[TestMethod] 
[ExpectedException(typeof(MeetingFutureException))] 
public void MeetingNoteSave_WithFutureDate() 
{ 
    _repository.MeetingNoteSave(1, "My note", true, "[email protected]"); 
} 

Убедитесь, что только один тест для каждого возможного потока вашей программы: 2 исключения означает 2 теста. Лично я мог бы избежать создания конкретных подклассов и просто использовать ArgumentException, но это зависит от вас, чтобы решить. Если у вас есть выразительные имена тестов, а код достаточно самодокументирован, вы будете знать, к чему в любом случае относится ссылка.

+0

спасибо. Кроме того, вы можете показать мне свой подход с помощью ArgumentException? –

+1

Это то же самое, что и выше, только вы используете '[ExpectedException (typeof (ArgumentException))] и' throw new ArgumentException («meeting»); '. Затем импортируется имя метода: SaveMeetingNote_WithNullMeeting_ThrowsArgumentException' и аргументы: '_repository.SaveMeetingNote (VALID_ID, INVALID_NAME, VALID_ISINVITED, VALID_EMAIL);' которые являются константами, которые вы определяете до этого. Тогда нет вопроса о том, что вы имели в виду. –

Смежные вопросы