C# – Should all class public methods come from an interface

cinterfacesnunittddunit testing

I'm currently learning about TDD techniques, one of the suggestion is to test only public methods and skip the private ones. I have also been reading about Mocking. If I want to mock a certain method, then it needs to come from an interface or be marked as virtual. When I start developing my application I don't know which methods I will want to mock while creating unit tests, because of that I think it's best to make them all available for mocking.

I assume that making all methods virtual isn't the best solution, then the alternative is the interface approach mentioned above.

Is that the right direction or do I miss something obvious?

Best Answer

  • Fabio touched on it in his comment - it is perfectly legit to start using a dependency in a test before any interface or implementation code exists for it.

    When you feel that your object under test needs indirect input from somewhere else, or that you need to test indirect outputs of your object, start typing your stubbing or mocking code as if those external dependencies existed. Then use IDE productivity features to generate the interfaces and their method signatures.

    This is called "programming by wishful thinking" and is used a lot in outside-in TDD.

    Your question makes less sense in that context, since you wouldn't create any new interface or any method inside an existing interface without mocking them first.

  • Another context is when you create dependencies by extracting new classes during the Refactor step of the TDD cycle and, in a more "Classicist" style, decide not to test them with mocks.

    Here, the answer to your question Should all class public methods come from an interface? is clearly: "no". You can perfectly have a TDD-written test that tests objects A and B without either of them implementing an interface.

    However, I would use this approach only when the extracted dependency is in the same layer as the object under test, not at application boundaries/seams. Having interfaces at architectural boundaries is often more valuable because it is usually where you get the most fragility, the least performance, the most complex configuration, and the highest likelihood of needing multiple implementations of the same abstraction.