TDD 和受保护的方法

TDD and Protected Methods

我正在尝试通过创建现有 MVC 应用程序的副本来学习 TDD,但我正在使用 TDD 从头开始​​创建它的副本。

在我现有的应用程序中,我有一个 Application_AuthenticateRequest 方法,如下所示。

这是受保护的。我认为不应测试这些方法是否正确 - 即您应该只测试 public 方法而不是私有和受保护的方法。如果这是真的,那么我会在下面编写我的受保护方法而不为其编写任何测试吗?

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        StaticDataSeeder.Seed();
    }

    protected void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
        HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];

        if (authCookie == null) return;

        var authTicket = FormsAuthentication.Decrypt(authCookie.Value);

        if (authTicket == null) return;

        var userData = new UserDataModel(authTicket.UserData);

        var userPrincipal = new PaxiumPrincipal(new GenericIdentity(authTicket.Name), null)
        {
            Email = userData.Email,
            Menu = userData.Menu,
            RememberMe = userData.RememberMe
        };

        Context.User = userPrincipal;
    }
}

仅仅进行测试并不能使其成为 TDD。如果您已经假设私有方法可以做某事,那么开发不是由测试驱动的,对吗?

试着先盲目地编写测试,你可能最终根本不需要私有方法,甚至可能将它作为另一个 class.

中的 public 方法

是的,你的测试用例是正确的,你只能测试你可以调用的方法。所以通常 public 方法是可测试的。同样,如果您的组件中有私有方法,则意味着它必须由该组件中的至少一个 public 方法调用。因此,当您测试 public 方法时,您也在同一个测试中测试私有方法的功能。您可以将私有方法视为 public 方法的几行,将 public 方法排除在外,使代码更具可读性和可重用性。

受保护的方法在您正在创建的 class 和它的未来子项之间创建契约。如果您不想创建此合同,则可以将这些方法定义为私有的,而不是受保护的。因此,我认为您应该测试这些方法的行为是否符合任何派生 classes 所期望的期望。

考虑两个 classes:

public abstract class BaseMathsClass {
    protected int Mult(int a, int b) {
        return a * b;
    }
}

public class ConcreteMathClass : BaseMathsClass {
    public int Square(int x) {
        return Mult(x, x);
    }
}

如果您乐于在 ConcreteMathClass 的测试中测试 Mult 方法的功能,那么您不需要为基础 class 编写测试。但是,如果您确实为基础 class 编写测试,这会在编写基础 class 时巩固合同,并且意味着任何派生的 classes 都知道他们正在签署什么起来。你站在栅栏的哪一边,取决于你的意见。 This question有一些其他意见。

你还说你认为你不需要测试私有方法。这是真的,因为您不需要编写特定的测试来直接调用私有方法,但是您应该通过针对 class 的 public 方法的测试隐式测试任何私有方法的功能.编写测试时,您不必真正关心 class 是否具有以下任一实现:

实施 1

class MyClass {
    public int GetSquare(int someValue) {
        return someValue * someValue;
    }
}

实施 2

class MyClass {
    public int GetSquare(int someValue) {
        return Mult(someValue, someValue);
    }

    private int Mult(int a, int b) {
        return a * b;
    }
}

使用 实现 2,您不需要编写专门调用 Mult 的测试,GetSquare 的测试足以练习此代码。这并不意味着您只需编写另一个私有方法 Add,因为目前您的 public 接口上不需要它。

您可能也对 this question 的答案感兴趣。