我正在查看我为电子邮件服务(使用SMTP)编写的单元测试,我想知道一项测试是否足够。这是我的电子邮件服务的片段:
[PluginFamily("EmailService")]
public interface IEmailService
{
Boolean SendEmail( string toAddress, string fromAddress, string bccAddress, string ccAddress, string subject,
string body, bool html );
}
[Pluggable("EmailService")]
public class EmailService : IEmailService
{
private IConfigurationReader _configReader;
public EmailService(IConfigurationReader configurationReader)
{
_configReader = configurationReader;
}
public bool SendEmail( string toAddress, string fromAddress, string bccAddress, string ccAddress, string subject, string body, bool isHtml )
{
MailMessage email = new MailMessage();
try
{
if (_configReader.TestMode)
{
toAddress = _configReader.TestEmailAddress;
}
}
//send email here
}
}
我正在嘲笑IConfigurationReader(基本上是ConfigurationManager的包装器)并将测试模式设置为true,以便测试我是否可以在“测试模式”下发送电子邮件。所以我的单元测试看起来像这样(这是我对该方法的单元测试之一。我有100%的代码覆盖率):
[Test]
public void Validate_Send_Email_In_Test_Mode()
{
bool result;
MockRepository mockRepository = new MockRepository();
var mockConfigReader = mockRepository.StrictMock<IConfigurationReader>();
using (mockRepository.Record())
{
SetupResult.For(mockConfigReader.TestMode).Return(true);
SetupResult.For(mockConfigReader.TestEmailAddress).Return("test@test.com");
SetupResult.For(mockConfigReader.EmailContentLocation).Return("test");
SetupResult.For( mockConfigReader.SmtpHost ).Return( "test.mail.com" );
}
ObjectFactory.InjectStub(typeof(IConfigurationReader), mockConfigReader);
emailService = ObjectFactory.GetInstance<IEmailService>();
using (mockRepository.Playback())
{
result = emailService.SendEmail( "testemail@test.com",
"test@test.com", "", "",
"this is a unit test - config in test mode", "body of unit test", true );
}
Assert.That( result, Is.True );
ObjectFactory.ResetDefaults();
}
这足以进行单元测试吗?我该怎么做才能改善它?
我担心只检查我的方法返回true是不够的单元测试。
答案 0 :(得分:2)
改善code coverage(所有类型)
答案 1 :(得分:2)
我建议您在满足各种可能的错误条件时包含“成功”的否定测试。例如,传入无效的电子邮件地址并验证是否返回了正确的错误代码和/或异常。
您可能还想模拟实际的SMTP服务器。虽然我没有做太多的搜索,但我找到了this SMTP server mock site。我在Java项目的电子邮件插件测试中使用了与此类似的方法。这样你就不在乎它是在“测试模式”还是生产中。唯一的区别是配置中的服务器/端口组合。这样做的另一个好处是确保您不仅仅是测试“测试代码”。
答案 2 :(得分:2)
发送电子邮件失败了吗?如果可以的话,你至少要测试两个案例,而你的单一测试是不够的。
由于你有一个布尔返回值,这会告诉我你期待两个返回代码之一,所以你再也没有测试所有可能性。
更不用说,在发送电子邮件时,返回值是函数结果中最不重要的:电子邮件是否已发送?
答案 3 :(得分:1)
我会说这部分:
{
if (_configReader.TestMode)
{
toAddress = _configReader.TestEmailAddress;
}
}
代码味道。您应该传入脚趾邮件地址,并确保使用您作为方法参数传入的内容调用该服务,并使用模拟确保它已正确发送到电子邮件api。换句话说,模拟电子邮件api,不要将模拟作为测试主体使用。
这可能有助于您尝试以相反的方式编写,首先进行测试,只有在您可以进行编写证明编写它的测试时才会编写生产代码。