单元测试:绕过或模拟调用静态电子邮件助手

Bob*_*way 1 c# unit-testing

道歉 - 这可能是重复的.但我无法在网站的其他地方找到有用的答案.

目前正致力于向应用程序添加电子邮件发送功能.它不是在TDD下完成的,但我们已经建立了测试,并且具有良好的覆盖范围.

我的任务是将电子邮件调度添加到现有功能.

public ActionResult RequestApproval(int? id)
{
    Job job = rep.GetJob(id);
    //widgets

    job.IsApproved = true;
    SaveJob(job);
}
Run Code Online (Sandbox Code Playgroud)

这是通过静态助手类完成的:

public static class EmailHelper
{
    public static void SendEmail(string subject, string body, params string[] to)
    {
         //gubbins
    }
 }
Run Code Online (Sandbox Code Playgroud)

所以我补充道

EmailHelper.SendEmail("Approval", "Please approve a thing", job.UsersWhoCanApprove.Select(a => a.Email).ToArray());
Run Code Online (Sandbox Code Playgroud)

到RequestApproval函数.

我知道我可以通过摆弄配置来有效地测试电子邮件传递功能,但我不想在这里这样做.在第一个实例中,它很慢,在第二个实例中,测试属于静态类的测试套件.

您不能将接口放在静态类上.那么我怎么能重构这个,我可以嘲笑或绕过对静态类的调用?

L-F*_*our 5

只需创建一个接口和一个实现:

public interface IEmailService
{
    void SendEmail(string subject, string body, params string[] to);
}

public class EmailService : IEmailService
{
    public void SendEmail(string subject, string body, params string[] to)
    {
         //gubbins
    }
 }
Run Code Online (Sandbox Code Playgroud)

然后,如果您针对接口进行编程,例如构造函数注入实际实现,则可以使用模拟框架轻松地在测试中模拟此电子邮件服务,或者只是创建电子邮件服务的虚拟实现.当然,在您的真实逻辑中,您使用真正的EmailService实现.

实际上,您很少需要在代码中使用真正的静态类(除非您有扩展方法等).如果您注入这样的实例并针对接口进行编程,那么它就更加灵活和模块化.