2014-10-19 159 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 + "'"); 
      } 
     } 

因此,方法可以抛出两种例外 - 会议不是在所有的这些参数或时相比,当前时间满足更多的时间存在(当应该过去或现在)。

现在,我正在写单元测试。简单的方法:

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

当然,呼叫单元测试会失败,并带有一些参数。我想抓住这些情况,所以,测试应该是成功的。我可以通过2种方式来完成。第一个是简单的,但有点脏:

 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向我展示你的方法吗? – 2014-10-19 09:48:30

+1

它和上面完全一样,只有你使用'[ExpectedException(typeof(ArgumentException))]''并抛出新的ArgumentException(“meeting”);'。那么什么是导入,从方法的名称中明确指出:'SaveMeetingNote_WithNullMeeting_ThrowsArgumentException'和参数:'_repository.SaveMeetingNote(VALID_ID,INVALID_NAME,VALID_ISINVITED,VALID_EMAIL);'这些是您在此之前定义的常量。那么你的意思是没有问题的。 – 2014-10-19 09:51:33