我需要关于软件测试的指导。
我过于复杂化了事情,但我太固执了,看不到我做错了什么,或者有其他方法可以完成任务。
我有几个公共方法都使用同一个私有方法。
私有方法本身:
- 必须处理其特定角色的许多场景 - 与同一实例中的字段/属性/方法密切配合
假设私有方法需要5个测试用例来覆盖所有场景,并且被6个公共方法使用。
问题:
- 我是否需要至少5x6个测试用例? - 如何重复使用私有方法的测试用例来测试每个公共方法? - 是否有任何关于重构重复测试的示例/文章?
例如:
OnStartup()
更新 #2
这样,如果我需要为私有方法的行为添加新的测试用例,我只需要在“BehaviourTest”中添加一次,所有包含它的公共方法测试都将被更新。
我过于复杂化了事情,但我太固执了,看不到我做错了什么,或者有其他方法可以完成任务。
我有几个公共方法都使用同一个私有方法。
私有方法本身:
- 必须处理其特定角色的许多场景 - 与同一实例中的字段/属性/方法密切配合
假设私有方法需要5个测试用例来覆盖所有场景,并且被6个公共方法使用。
问题:
- 我是否需要至少5x6个测试用例? - 如何重复使用私有方法的测试用例来测试每个公共方法? - 是否有任何关于重构重复测试的示例/文章?
例如:
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
我考虑使用策略模式封装私有方法,这样我就可以独立地测试它(以及公共方法)。
然而,我不想使用它的原因是:
- 我没有意图在运行时具有可互换的行为
- 仅仅为了更容易地进行测试而使用该模式似乎是错误的
更新 #1
我的问题涉及测试私有方法行为的公共接口。但是我最终会得到很多重复的测试方法(请参见上面的示例)。
使用策略模式,我认为我只需要:
- 测试策略中的所有路径(本质上是测试私有方法)
- 验证所有公共方法都调用了策略(可以轻松使用模拟对象,在此处验证是否已被调用)
但正如我所提到的,我认为我不应该仅仅为了更容易地进行测试而引入一个模式。除非我真的必须采用这种方法。
更新 #2
减少重复的第一次尝试:
将私有方法测试分组到自己的类中(Behaviour1Test)
- GetTestCases() 返回与此行为相关的测试用例列表
需要此测试的所有公共方法实现公开接口
- Arrange()
- Act()
- Assert()
例如:
// 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){}
}
这样,如果我需要为私有方法的行为添加新的测试用例,我只需要在“BehaviourTest”中添加一次,所有包含它的公共方法测试都将被更新。