-1

I'm used to an approach in unit testing to cover each method with a separate unit test. Including private methods by marking them as internal virtual (C#) and creating a separate unit test for them. Recently I can't find a single person who supports this approach in my company - the preferred way is to write a single unit test for a public method, even if it contains calls to another private method(s), in which case all dependencies in those private methods must be mocked as well. I'll give a simple example on top of my head:

public async Task DoSomeWorkAsync()
{
    await repo.SaveStateAsync();
    await DoSomeAdditionalWorkAsync();
    Console.WriteLine("Done");
}

private async Task DoSomeAdditionalWorkAsync()
{
    await repo.GetDataAsync();
    await repo.GetAnotherDataSetAsync();
}

In an example above my colleagues say it's right way to go is to set up stubs for all 3 methods being called (SaveState, GetData, GetAnotherData) so single unit test will execute both public and private methods and check both. The way I'm used to do it is to declare method as internal virtual, so method would become visible to an assembly with tests, and writing a separate test for DoSomeAdditionalWorkAsync method first and then using partial mock to mock DoSomeAdditionalWorkAsync method when writing another unit test for DoSomeWorkAsync method.

I heard the argument that if private method is used only in one place and was created for code readability reason then it's fine to have a single unit test. But in that case there's a risk for next developer to re-use private method with assertion it's already covered in a separate test. Does the answer depend on complexity of a private method itself? (the bigger private method, more reasons to add unit test for it)

Am I in the wrong here? Should I stick to my colleagues' recommendations? I tried to search for this topic but not sure what keywords to look for here. What are best practices/recommendations for such a simple scenario?

Thanks in advance for any kind of opinion or advice.

user970694
  • 139
  • 1
  • 3
  • 8
  • 1
    Does this answer your question? [How do you unit test private methods?](https://stackoverflow.com/questions/250692/how-do-you-unit-test-private-methods) Straight up asking for opinions is off-topic for SO, but the question has already received plenty of attention over the years. I would argue that if you have big private methods worthy of testing, then your class is too complicated, and you should consider splitting things up in more classes with these methods `public` -- if the classes are not suitable for external use make them `internal` and use `InternalsVisibleTo`. – Jeroen Mostert May 18 '22 at 09:07
  • https://stackoverflow.com/questions/250692/how-do-you-unit-test-private-methods is not a duplicate of this question – Eamonn McEvoy May 18 '22 at 09:22
  • @JeroenMostert thanks for the link. I was rather looking for an answer if you should cover private methods with unit tests separately from public methods, not the implementation details. However, some of the answers to that question discuss it from different perspectives. – user970694 May 18 '22 at 09:36
  • 1
    The question of whether you *should* is purely opinion based and as such not a good fit for SO -- you can test anything you like in any way you want, technically, and while people may have great opinions buttressed by arguments on whether that's good or bad, that's not what we're looking for on SO. The linked question definitely covers the ground in the opinion department as well, though (unavoidably). – Jeroen Mostert May 18 '22 at 09:40
  • that's true, but it is what I was looking for - people's opinions based on their experiences. If you feel this is a bad question for SO, feel free to delete it. Thanks to everybody sharing their opinions here. – user970694 May 18 '22 at 09:47

2 Answers2

1

The short answer is that you shouldn’t test private methods directly, but only their effects on the public methods that call them. Unit tests are clients of the object under test, much like the other classes in the code that are dependent on the object. In fact, if you are practicing test-driven development (TDD), the unit test is your first client of the object. The test should only be accessing the class’ public interface. If an object is hard to test via its public interface, it is going to be hard to use in the production code. This is one of many examples where a unit test is exposing potential design issues.

SValley_Dev
  • 638
  • 4
  • 8
1

The idea is that your class exposes a an interface and your tests verify the input/output is correct from that interface. Each class/method should have a single responsibility.

The technique you described of marking a method as protected virtual is one that I have used myself on occasion, but this was within the context of a large legacy code application where it was impractical to refactor everything into a testable state right away. This technique should be used sparingly.

Generally if you feel that a private method is complex enough that it needs its own tests you should probably extract it out to its own class. If the private method does not have a lot of complexity then you will be needlessly asserting implementation details and making your code hard to refactor in future.

If you need to set up many mock objects to test a single class then it is probably violation SRP. One of the great side affects of writing tests is that it highlights any poorly designed classes.

I highly recommend this book to you: https://www.artofunittesting.com/

Eamonn McEvoy
  • 8,876
  • 14
  • 53
  • 83