4

I am trying to learn TDD by creating a copy of an existing MVC app I have but I am creating a copy of it from scratch using TDD.

In my existing app I have an Application_AuthenticateRequest method as shown below.

This is protected. Am I right in thinking that these methods should not be tested - ie you should only test public methods and not private and protected ones. If this is true then would I just code away my protected method below without writing any tests for it?

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;
    }
}
Dave Amour
  • 155
  • 1
  • 13
  • I think you need to read this [article](http://www.codeproject.com/Articles/9715/How-to-Test-Private-and-Protected-methods-in-NET) it could be useful for you – Baximilian May 27 '15 at 06:17
  • Regarding this having been asked before - I can easily search for this question as I am sure it has been asked before many times on this site and many others. I like to engage with people conversationally though and sometimes don't want to just google something - I want human interaction. – Dave Amour May 29 '15 at 06:16
  • I think if you had tailored your question to your specific case, which is that you want to know if you / how you should go about using TDD when you're creating a class that fits into an existing ecosystem and needs specific extension points, it's less likely that the question would have been closed as a duplicate and you would have got more relevant answers as a starting point (the currently highest voted answer for example doesn't particularly seem to address the question you seem to have had in mind). – forsvarir May 29 '15 at 08:40
  • Yes you are right I suppose, my bad. – Dave Amour May 29 '15 at 10:49

3 Answers3

3

Just having tests doesn't make it TDD. If you already assume private method that does something, Development wasn't Driven by Tests, was it?

Try to go blind and write tests first, you might end up not needing the private method at all or even having it as a public method in another class.

DevNewb
  • 841
  • 7
  • 19
  • My code is actually being hooked into the pipeline of an MVC app - it is not some simple api I am invoking. It needs to be where it is hence my uncertainty on how this should be handled. – Dave Amour May 29 '15 at 06:18
1

Yes you are correct with your test case you can only test the methods which you can invoke. So generally public methods are testable. Again, if you have a private method in your component that means it must be invoked by at least one public method in that component. So while you are testing you public method , you are also testing the private method's functionality in the same test. Private methods you can consider as few lines of the public method keeping out side that public method to make the code more readable and for re-usability purpose.

Manmay
  • 835
  • 7
  • 11
  • I'm not invoking the public methods though - they are inside the pipeline of an MVC app. – Dave Amour May 29 '15 at 06:19
  • If you want to follow TDD, You should write test cases to test your public method of your components individually (mocking the necessary dependencies) , regardless how and where it is used in your framework. – Manmay May 29 '15 at 07:35
0

Protected methods create a contract between the class you're creating and it's future children. If you didn't want to create this contract, you'd be defining the methods as private, not protected. As such, I'd argue that you should be testing that the behaviour of those methods matches the expectations that any derived classes would expect.

Consider an two 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);
    }
}

If you're happy testing the functionality of the Mult method in your tests for ConcreteMathClass, then you don't need to write tests for the base class. However, if you do write tests for the base class, this cements the contract at the time that the base class is written and means that any derived classes know what they're signing up for. Which side of the fence you come down on, depends on your opinion. This question has some other opinions.

You also say that you believe you don't need to test private methods. This is true in that you don't need to write specific tests to call private methods directly, however you should be testing the functionality of any private methods implicitly through your tests against the public methods of a class. When writing your tests, you shouldn't really care if your class has either of the following implementations:

Implementation 1

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

Implementation 2

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

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

With implementation 2, you don't need to write a test that specifically calls Mult, the tests for GetSquare sufficiently exercise this code. This doesn't mean you would just code up another private method Add, because at the moment there isn't a need for it on your public interface.

You may also be interested in the answers to this question.

Community
  • 1
  • 1
forsvarir
  • 10,749
  • 6
  • 46
  • 77
  • I am not invoking or writing the public methods in this case - it is all in the pipeline of the MVC app. – Dave Amour May 29 '15 at 06:21
  • @DaveAmour The behaviour still needs to be tested, or it shouldn't be there. Depending on what the method does, you might decide that testing it in place (in this instance through an integration test) is easier / more appropriate than unit testing it in isolation, This decision is essentially the same as the one I've indicated above where you need to decide if you test the class with the protected methods, or you are happy to consider them a part of a bigger unit and test them implicitly through the classes that use them. – forsvarir May 29 '15 at 08:18
  • Ok thanks - its this grey area of subjective decision making I'm struggling with. Could really do with some real TDD work with some experience developers but just having to do it all on my own at home at the mo. – Dave Amour May 29 '15 at 10:58
  • @DaveAmour even in good teams it's still very subjective between the zealots and the pragmatists. Personally I think the best approach to getting started is to try going 100%test first for a while, work on some if thetechniques to make your code more unit testable and then figure out what constitutes a unit to you and when integration testing is the better way to go, so you are ready for the *discussions* if you ever find somewhere doing TDD. I don't really use it, but it may be worth seeing if there is an appropriate room on chat to get some feedback from others. – forsvarir May 30 '15 at 15:48
  • Thanks - good advice. I also had an idea about extracting my code in Application_AuthenticateRequest and putting it in a separate class and then I can just call that from Application_AuthenticateRequest and test the class seperatley (with various mocks of course)! – Dave Amour May 31 '15 at 05:22