如何为使用线程的方法编写单元测试。
在下面的例子中如何测试someMethod方法?
public class SomeClass {
private final SomeOtherClass someOtherClassInstance = IoC.getInstance(SomeOtherClass.class);
private final ExecutorService executorService = Executors.newCachedThreadPool();
public void someMethod() {
executorService.execute(new Runnable() {
@Override
public void run() {
someOtherClassInstance.someOtherMethod();
}
});
}
}
为此目的,java和.net中是否有任何解决方案?
答案 0 :(得分:4)
你的问题是'什么是单元测试'(UT)。 UT只是自动化测试的一种形式。在这种情况下,您的问题意味着代码调用操作系统来启动一个线程,因此根据定义,测试它的测试不是单元测试,但可能是集成测试。
为什么我用似乎语义的东西打扰你,理解测试的意图使编写测试和构造代码变得如此容易。那里的工作代码量大于可测试代码的数量。
那么,如何将此代码更改为可单元测试(我将跳过'为什么要打扰的东西')......
C#中的单元测试测试单个类型(您的类)......重要的是(根据定义)没有别的。所以你的代码需要反映这一点。你要测试的是,当我打电话给ABC时,它会做这件事。这些东西包括启动一个线程。所以你想测试一下这个方法来启动一个被调用的线程。这里的基本原则是你的应用程序需要一个线程,这就是你的断言。
那怎么样?为线程创建创建代理,也许是工厂。然后你可以在单元测试中断言它被调用以及它是如何被处理的。听起来很难,但是当你养成习惯时,这很容易。
BTW,Resharper为OS类型(例如线程)创建代理。在他们的帮助中查看委派成员的内容。如果你不使用Resharper,你应该是。是的,我知道这不是你跳过的答案,但请相信我这是你需要的答案。
我觉得考虑类别中的测试很有用:
答案 1 :(得分:2)
如果有另一个线程,则必须等到调用该方法。您必须决定在考虑未调用方法之前应等待多长时间,没有可以为您执行此操作的工具。
当然,你可以模拟ExecutorService在当前线程中运行并避免问题。
答案 2 :(得分:2)
jMock团队在'jMock Cookbook: Test Multithreaded Code'中描述了一种杰出的Java方法。在与测试相同的线程上执行“线程”功能的概念也可以应用于C#代码(请参阅this blog post)。 C#测试看起来像这样:
[Test]
public void TestMultiThreadingCodeSynchronously()
{
// Arrange
SomeOtherClass someOtherClassMock = MockRepository.GenerateMock<SomeOtherClass>();
DeterministicTaskScheduler taskScheduler = new DeterministicTaskScheduler();
SomeClass systemUnderTest = new SomeClass(taskScheduler, someOtherClassMock);
// Act
systemUnderTest.SomeMethod();
// Now execute the new task on
// the current thread.
taskScheduler.RunTasksUntilIdle();
// Assert
someOtherClassMock.AssertWasCalled(x=>x.SomeOtherMethod());
}
您的“受测试系统”将如下所示:
public class SomeClass
{
private readonly TaskScheduler taskScheduler;
private readonly SomeOtherClass instance;
public SomeClass(
TaskScheduler taskScheduler,
SomeOtherClass instance)
{
this.taskScheduler = taskScheduler;
this.instance = instance;
}
public void SomeMethod()
{
Task.Factory.StartNew(
instance.SomeOtherMethod,
new CancellationToken(),
TaskCreationOptions.None,
taskScheduler);
}
}
在this blog post中详细描述了C#解决方案。