我目前正在开展一个需要我们编写单元测试的项目。这是我的知识有限的领域。经过最近几天的研究,我看到了多个示例,展示了如何编写基本测试,断言字符串是否等于另一个字符串。
但是,我仍然不清楚如何整体进行单元测试。我有一个示例方法,我需要在下面测试:
public static SearchResults GetSearchResults(SearchFormModel searchForm, int currentItemCount, int skip)
{
var results = new SearchResults();
var client = new RestClient(Settings.Default.SearchWebServiceUrl);
try
{
var request = new RestRequest("{0}", Method.GET);
if (!searchForm.FirstName.IsNullOrEmpty()){request.AddParameter("forenames",searchForm.FirstName);}
if (!searchForm.LastName.IsNullOrEmpty()) { request.AddParameter("surname", searchForm.LastName); }
request.AddUrlSegment("0", "Basic");
request.AddHeader("Accept", "application/json");
var response = client.Execute<SearchResult>(request);
if (response.ResponseStatus != ResponseStatus.Completed)
{
if (response.ErrorException != null)
{
SendErrorEmail(response.ErrorException.Message);
}
throw new Exception(Settings.Default.SearchGenericError);
}
if (response.Data != null)
{
results.Valid = response.Data.Valid;
var error = response.Data.Error;
if (!string.IsNullOrEmpty(error)){error = Settings.Default.SearchGenericError;}
results.Error = error;
if (response.Data.SearchResults != null)
{
results.SearchResults = new List<SearchResult>(response.Data.SearchResults );
}
}
else
{
throw new Exception(Settings.Default.SearchGenericError);
}
}
catch (Exception ex)
{
registrantList.Error = ex.Message;
}
return results;
}
这里有一个好的方法是将两个分解为两个单独的方法吗?一个设置请求并获得响应的方式:
public static SearchResults GetSearchResults(SearchFormModel searchForm, int currentItemCount, int skip)
{
var results = new SearchResult();
var client = new RestClient(Settings.Default.SearchWebServiceUrl);
try
{
var request = new RestRequest("{0}", Method.GET);
if (!searchForm.FirstName.IsNullOrEmpty()){request.AddParameter("forenames",searchForm.FirstName);}
if (!searchForm.LastName.IsNullOrEmpty()) { request.AddParameter("surname", searchForm.LastName); }
request.AddUrlSegment("0", "Basic");
request.AddHeader("Accept", "application/json");
var response = client.Execute<SearchResult>(request);
return GetSearchResults(response);
}
反过来又返回另一个应该可测试的方法,即:
public static SearchResults GetSearchResults(IRestResponse<SearchResults> response)
{
var results = new SearchResult();
if (response.ResponseStatus != ResponseStatus.Completed)
{
if (response.ErrorException != null)
{
SendErrorEmail(response.ErrorException.Message);
}
throw new Exception(Settings.Default.SearchGenericError);
}
if (response.Data != null)
{
results.Valid = response.Data.Valid;
var error = response.Data.Error;
if (!string.IsNullOrEmpty(error)){error = Settings.Default.SearchGenericError;}
results.Error = error;
if (response.Data.SearchResults != null)
{
results.SearchResults = new List<SearchResult>(response.Data.SearchResults );
}
}
else
{
throw new Exception(Settings.Default.SearchGenericError);
}
}
catch (Exception ex)
{
registrantList.Error = ex.Message;
}
return results;
}
为初学者问题道歉,但我想确保这种方法是可行的方法。这是正确的接近方式吗?
提前致谢
答案 0 :(得分:1)
单元测试的最佳方法是在编写将使它们通过的代码之前编写测试。以这种方式工作可能会使您编写更小,更容易测试的类和方法 - 即松散耦合的代码。回想一下经验法则,类应该有一个责任,方法应该做一件事。
如果你需要围绕这里显示的代码进行测试,你肯定有正确的想法来分解这些方法 - 我认为你可以提取许多小得多的方法。如果一个方法的名称能够揭示出它所做的事情的意图,那么很难让方法太小。
您熟悉依赖注入和模拟对象库吗?就个人而言,如果没有它们,我就不会编写单元测试(不是绝对的,当然也不是大多数)。我不熟悉.Net领域中的可用内容,但我们的想法是你安排你的类明确依赖于各种协作者,你使用模拟对象库轻松地将这些协作者放到完全正确的状态充分锻炼你的考试科目。依赖注入框架将帮助您依赖接口而不是具体的类 - 另一个好的经验法则。
编辑:认为这个答案会从一些更实用的建议中受益,所以我记得安德鲁·宾斯托克在杰夫贝的原创论文&#34;对象健美操&#34;上发表的this帖子。我将理解,如果您对提出的建议的初步反应令人难以置信,但我坚信,没有更快的方法来加快您想要开发的实践。 Francesco Cirillo的anti-if campaign提供了另一种关于如何管理代码复杂性的观点。答案 1 :(得分:1)
我基本同意@ unigeek的回答。您将不得不按责任分解您的课程,然后使用依赖注入(DI)来模拟协作者。没有这个单元测试变得非常困难或不可能。
,例如,您不希望测试实际触发REST请求并发送电子邮件。因此,您必须将这两个职责提取到他们自己的类中,您可以模拟它们。
Mark Seemann's book on DI极大地帮助我绕过它。
对于模拟,我喜欢使用NSubstitute,因为我发现它易于使用且轻量级。
尽量花时间阅读这些主题。单元测试很难,但如果做得好,它会大大提高您的代码质量,并使您成为更好的开发人员IMO。