我有管理多个线程可能使用的信息的字段。访问这些字段非常重要,因此我实例化了一个信号量:
Semaphore semaphore = new Semaphore(1);
每个方法都试图获取信号量,如果没有,则基本上锁定:
public void method()
{
semaphore.acquire();
doStruff();
cleanUp()
}
//Other methods using the same basic layout as the method above.
public void cleanUp()
{
//watch for state consistency and do some clean up
semaphore.release();
}
我如何知道以下内容来测试上述内容:
Thread.sleep(x)
使用{{1}}进行定时测试,因为该方法存在固有问题,例如对时钟的依赖以及缺乏对该方法的信任。代码的位数足够小,我可以很好地确定它不会死锁或上面详述的条件被违反。然而,一个好的测试案例可能会给它带来更多的重量,当然会增加信心。
答案 0 :(得分:1)
这是一个测试气味的例子,可以说应该激励代码更改。代码很难测试,因为它在应用程序逻辑职责中混淆了同步职责。通常,确保此类代码正确运行非常困难。
最好将与同步相关的代码提取到一个单独的类中,该类本身是可测试的,并使用依赖注入来允许测试模拟该接口。
e.g。
public interface ResourceGuard<T> {
void accessResource(Consumer<T> consumer);
}
public class ExclusiveResourceGuard<T> implements ResourceGuard<T> {
private final T instance;
private final Semaphore semaphore;
public ExclusiveResourceGuard(final T instance) {
this.instance = instance;
}
public void accessResource(Consumer<T> consumer) {
semaphore.acquire();
consumer.consume(instance);
semaphore.release();
}
}
现在,您可以通过传入假冒的消费者来测试此类,该消费者对测试范围的数据起作用,并确保正确同步访问。
然后您的生产消费者类可以拥有注入的资源保护......
public class StuffDoingClass {
private final ResourceGuard<MyThing> myThing;
public StuffDoingClass(final ResourceGuard<MyThing> theThing) {
this.myThing = theThing;
}
public void method() {
this.myThing.accessResource(this::doStuff);
}
private void doStuff(final MyThing theActualThing) {
theActualThing.method(...);
}
}
现在这个类可以通过一个足够简单的ResourceGuard模拟来测试。
从设计的角度来看,错误地访问资源也更加困难(没有持有锁)。我知道这个答案违背了你的无代码更改&#39;授权,但在这种特殊情况下,您似乎不太可能满足所有要求。
答案 1 :(得分:0)
看看JMeter。
它允许您以多种方式启动代码的多个实例。为了确保您确实看到多线程访问,请考虑在JMeter测试计划中使用多个线程组。
仅供参考:我发现在线程上对要更新的实际对象进行同步时非常有用。这允许您以受控方式控制多个变量的更新,并且非常自我记录。它看起来像这样......
同步(变量) {
}
以上几乎可以出现在任何方法中,甚至是构造函数。