I need some guidance with my software testing.
I’m over-complicating things, but I’m too fixated to see what I’m doing wrong, or an alternate way of doing things.
I have several public methods that are using the same private method.
The private method itself:
- has to handle many scenarios for its specific role
- works closely with fields/properties/methods in the same instance
Say that the private method needs 5 tests to cover all scenarios, and is used by 6 public methods.
Question
-
Do I then need at least
5x6tests? -
How can I re-use the private method’s tests for each public method?
-
Are there any examples/articles out there on refactoring repeated tests?
Example
OnStartup()
- if_file_exists_load_entries ()
- if_file_missing_load_last ()
- if_no_files_create_new_entries ()
- if_exception_clear_entries_and_log ()
- loaded_entries_init_called ()
- Other tests
OnUserLoadCustom()
- if_file_exists_load_entries _AND_STORE_AS_LAST()
- if_file_missing_load_last _AND_STORE_AS_LAST_AND_WARNING_MESSAGE()
- if_no_files_create_new_entries _AND_WARNING_MESSAGE()
- if_exception_clear_entries_and_log _AND_ERROR_MESSAGE()
- loaded_entries_init_called _AND_SUCCESS_MESSAGE()
- Other tests
OnRecover()
- if_file_exists_load_entries _AND_INFO_MESSAGE()
- if_file_missing_load_last _AND_INFO_MESSAGE()
- if_no_files_create_new_entries _AND_INFO_MESSAGE()
- if_exception_clear_entries_and_log _AND_ERROR_MESSAGE_AND_SHUTDOWN()
- loaded_entries_init_called _AND_SUCCESS_MESSAGE()
- Other tests
I’m considering encapsulating the private method using the Strategy pattern, so I can test it (and the public methods) in isolation.
However, I don’t feel right using one because:
- I do not intend to have interchangeable behaviours at runtime
- Using the pattern for the sake of easier testing seems wrong
Update #1
My question pertains to testing the public interface for the private method’s behaviour. But I end up with lots of duplicate test methods (see my examples above).
With a strategy pattern, I reckon all I need are:
- Test all the paths in the strategy (essentially, testing the private
method) - Verify that all public methods invokes the strategy (Can easily use a mock object here, and verify that it’s been called)
But like I mentioned, I don’t think I should introduce a pattern just for the sake of easier testing. I’m holding off on this approach unless I really have to.
Update #2
First attempt at reducing duplication:
-
Private method tests grouped into its own class (Behaviour1Test)
- GetTestCases() returns list of test cases related to this behaviour
-
All public methods that needs this test implements interface that exposes
- Arrange()
- Act()
- Assert()
For example:
// Public method tests
[TestFixture]
public class PublicMethodTests: IBehaviour1Test
{
// Behaviour 1
Behaviour1Test _behaviour1;
IEnumerable<TestCaseData> Behaviour1TestCases{ get { return _behaviour1.GetTestCases(); } }
[Test]
[TestCaseSource("Behaviour1TestCases")]
public void RunBehaviour1Test(Action<IBehaviour1Test> runTestCase)
{
runTestCase(this);
}
// ==============================
// Behaviour 1 Arrange/act/assert
void IBehaviour1Test.Arrange(){}
void IBehaviour1Test.Assert(object result){}
object IBehaviour1Test.Act()
{
return _model.PublicMethod();
}
// Other tests
}
// Implement this in order to run Behaviour1 test cases
interface IBehaviour1Test
{
void Arrange();
object Act();
void Assert(object retValue);
}
// Collection of tests for behaviour 1
public class Behaviour1Test
{
// Generate test cases
IEnumerable<TestCaseData>() GetTestCases()
{
yield return new TestCaseData((Action<IBehaviour1Test>)Test_1);
yield return new TestCaseData((Action<IBehaviour1Test>)Test_2);
yield return new TestCaseData((Action<IBehaviour1Test>)Test_3);
}
void Test_1(IBehaviour1Test impl)
{
// Arrange
impl.Arrange(); // public method's arrange
Test1Setup(); // Arrange for this test
// Act
var result = impl.Act();
// Assert
Test1Assert(result); // Assert for this test
impl.Assert(result); // Assert on public method
}
void Test_2(IBehaviour1Test impl){}
void Test_3(IBehaviour1Test impl){}
}
This way, if I need to add a new test case for the private method’s behaviour, I just need to add it once in the BehaviourTest, and all public method tests that contains it will be updated.

You should apply the same philosophy in your tests as you do in your application code. If common functionality can be extracted into helper methods or classes then you should do so. It will save you the code duplication and will help you refactor later if the private method changes.
I imagine you have a lot of common setup, teardown, assert and verify code that could be generalized.