TDD和受保护方法

4

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

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

这是受保护的。 我是否正确地认为这些方法不应该被测试 - 也就是说,您只应该测试公共方法而不是私有和受保护的方法。 如果是这样,那么我是否只需编写没有任何测试的受保护方法?

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;
    }
}

我认为你需要阅读这篇文章,它可能对你有用。 - Baximilian
关于之前已经被问过的问题- 我可以很容易地搜索到这个问题,因为我确信它已经在这个网站和许多其他网站上被问过很多次。虽然我喜欢进行交流,但有时并不想只是通过谷歌搜索来寻找答案 - 我想要人与人之间的互动。 - Dave Amour
我认为,如果你针对你的具体情况提出问题,即当你创建一个适合于现有生态系统并需要特定扩展点的类时,你想知道是否/如何使用TDD,那么这个问题就不太可能被关闭为重复,并且你会得到更多相关的答案作为起点(例如,目前得票最高的答案似乎并没有特别涉及你所考虑的问题)。 - forsvarir
是的,你说得对,我想是我不好。 - Dave Amour
3个回答

3

仅仅拥有测试并不等同于TDD。如果你已经假设存在一个执行某些操作的私有方法,那么开发过程中就没有被测试驱动,是吗?

尝试盲目编写测试,并优先完成测试,你可能最终根本不需要这个私有方法,甚至可以将它作为另一个类的公共方法。


我的代码实际上被钩入了MVC应用程序的管道中 - 它不是我调用的一些简单API。它需要在那里,因此我对如何处理此事感到不确定。 - Dave Amour

1

是的,你对测试用例的理解是正确的,你只能测试可以调用的方法。因此,通常情况下只有公共方法是可测试的。同样,如果在组件中有一个私有方法,那就意味着该方法必须由该组件中至少一个公共方法调用。因此,在测试公共方法时,您也在同一测试中测试了私有方法的功能。可以将私有方法视为公共方法的几行代码,以使代码更易读,并且具有可重用性。


我并没有调用公共方法 - 它们在MVC应用程序的管道内部。 - Dave Amour
如果你想遵循TDD,你应该编写测试用例来单独测试组件的公共方法(模拟必要的依赖项),而不管它在框架中如何使用和在哪里使用。 - Manmay

0

受保护的方法为您正在创建的类和其未来子类之间创建了契约。如果您不想创建此契约,则将方法定义为 private,而不是 protected。因此,我认为您应该测试这些方法的行为是否符合任何派生类期望的预期。

考虑两个类:

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);
    }
}

如果您在测试ConcreteMathClassMult方法的功能时感到满意,那么您不需要为基类编写测试。然而,如果您确实为基类编写了测试,这将在编写基类时确定合同,并意味着任何派生类都知道他们正在签署什么。您对此的看法取决于您的观点。这个问题有一些其他的观点。

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

实现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,因为在公共接口上目前没有这个需要。

您可能还对 这个问题 的答案感兴趣。


我在这种情况下没有调用或编写公共方法 - 这都在MVC应用程序的管道中。 - Dave Amour
@DaveAmour 行为仍需测试,否则不应存在。根据方法的作用,您可能会决定通过集成测试在现场进行测试比独立单元测试更容易/更合适。这个决定与我上面提到的决定基本相同,在那里你需要决定是否测试带有受保护方法的类,或者你是否愿意将它们视为更大单位的一部分,并通过使用它们的类的隐含测试来测试它们。 - forsvarir
好的,谢谢 - 我正在苦恼于这个主观决策的灰色地带。真的很需要一些有经验的开发人员进行实际的TDD工作,但现在只能独自在家完成所有工作。 - Dave Amour
@DaveAmour 即使在好的团队中,狂热者和实用主义者之间仍然非常主观。就个人而言,我认为最好的方法是尝试先完全采用测试驱动开发一段时间,学习一些技巧来使您的代码更易于进行单元测试,然后确定对您来说什么构成了一个单元,并在何时集成测试是更好的选择,这样您就可以准备好进行讨论,如果您在某个地方进行TDD。我并不真正使用它,但值得看看是否有适当的聊天室可以从其他人那里获得反馈。 - forsvarir
谢谢 - 好建议。我也有一个想法,就是在Application_AuthenticateRequest中提取我的代码并将其放入一个单独的类中,然后我可以从Application_AuthenticateRequest调用它并分别测试该类(当然使用各种模拟)! - Dave Amour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接