我有几个实现某些接口的类。接口有一个契约,有些方法应该同步,有些不应该,我想通过单元测试来验证所有实现的合同。这些方法应该使用synchronized关键字或锁定在this
上 - 非常类似于synchronizedCollection()包装器。这意味着我应该能够在外部观察它。
如果我有一个线程调用iterator(),继续Collections.synchronizedCollection()的示例,我仍然可以使用另一个线程进入add()等方法,因为iterator()不应该执行任何锁定。另一方面,我应该能够在外部同步集合,并看到另一个线程在add()上阻塞。
有没有一种方法可以测试方法是否在JUnit测试中同步?我想避免长时间的睡眠陈述。
答案 0 :(得分:5)
如果你只是想检查一个方法是否有synchronized
修饰符,除了显而易见的(查看源代码/ Javadoc),你也可以使用反射。
Modifier.isSynchronized(method.getModifiers())
测试方法是否保证在所有并发方案中正确同步的更一般的问题可能是一个不可判定的问题。
答案 1 :(得分:4)
这些都是可怕的想法,但你可以这样做......
// Substitute this LOCK with your monitor (could be you object you are
// testing etc.)
final Object LOCK = new Object();
Thread locker = new Thread() {
@Override
public void run() {
synchronized (LOCK) {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
System.out.println("Interrupted.");
return;
}
}
}
};
locker.start();
Thread attempt = new Thread() {
@Override
public void run() {
// Do your test.
}
};
attempt.start();
try {
long longEnough = 3000 * 1000;// It's in nano seconds
long before = System.nanoTime();
attempt.join(longEnough);
long after = System.nanoTime();
if (after - before < longEnough) {
throw new AssertionError("FAIL");
} else {
System.out.println("PASS");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
locker.interrupt();
如果您知道在任何实现中始终调用参数上的方法,则可以传递伪装成参数的模拟对象并调用holdsLock()。
所以喜欢:
class Mock implements Argument {
private final Object LOCK;
private final Argument real;
public Mock(Object obj, Argument real){
this.LOCK=obj;
this.real = real;
}
@Overrides
public void something(){
System.out.println("held:"+Thread.holdsLock(LOCK));
this.real.something();
}
然后等待类在Argument上调用something()。
答案 2 :(得分:4)
非常感谢Zwei steinen撰写我使用过的方法。我完成的示例代码中存在一些问题,因此我认为值得在此处发布我的发现。
以下是Scala特征的同步测试代码:
trait SynchronizedTestTrait
{
val classUnderTest: AnyRef
class Gate
{
val latch = new java.util.concurrent.CountDownLatch(1)
def open()
{
this.latch.countDown
}
def await()
{
this.latch.await
}
}
def nanoTime(code: => Unit) =
{
val before = System.nanoTime
code
val after = System.nanoTime
after - before
}
def assertSynchronized(code: => Unit)
{
this.assertThreadSafety(threadSafe = true, millisTimeout = 10L)(code)
}
def assertNotSynchronized(code: => Unit)
{
this.assertThreadSafety(threadSafe = false, millisTimeout = 60L * 1000L)(code)
}
def assertThreadSafety(threadSafe: Boolean, millisTimeout: Long)(code: => Unit)
{
def spawn(code: => Unit) =
{
val result = new Thread
{
override def run = code
}
result.start()
result
}
val gate = new Gate
val lockHolderThread = spawn
{
this.classUnderTest.synchronized
{
// Don't let the other thread start until we've got the lock
gate.open()
// Hold the lock until interruption
try
{
Thread.sleep(java.lang.Long.MAX_VALUE)
}
catch
{
case ignore: InterruptedException => return;
}
}
}
val measuredNanoTime = nanoTime
{
// Don't start until the other thread is synchronized on classUnderTest
gate.await()
spawn(code).join(millisTimeout, 0)
}
val nanoTimeout = millisTimeout * 1000L * 1000L
Assert.assertEquals(
"Measured " + measuredNanoTime + " ns but timeout was " + nanoTimeout + " ns.",
threadSafe,
measuredNanoTime > nanoTimeout)
lockHolderThread.interrupt
lockHolderThread.join
}
}
现在让我们说我们想测试一个简单的类:
class MySynchronized
{
def synch = this.synchronized{}
def unsynch = {}
}
测试看起来如此:
class MySynchronizedTest extends SynchronizedTestTrait
{
val classUnderTest = new MySynchronized
@Test
def synch_is_synchronized
{
this.assertSynchronized
{
this.classUnderTest.synch
}
}
@Test
def unsynch_not_synchronized
{
this.assertNotSynchronized
{
this.classUnderTest.unsynch
}
}
}
答案 3 :(得分:1)
使用反射,获取方法的Method对象,并在其上调用toString()。 “synchronized”关键字应出现在toString()的输出中。