如何对同步方法进行单元测试?

elf*_*far 8 java testing unit-testing synchronized

说我有这样一个方法:

synchronized void incrementIndex() {
      index++;
}
Run Code Online (Sandbox Code Playgroud)

我想对这个方法进行单元测试,看看如果多个线程同时尝试增加索引,索引的最终值是否设置正确。假设我不知道方法声明中的“synchronized”关键字(并且我只知道方法的契约),我该如何进行测试?

ps 如果有帮助,我正在使用 Mockito 编写测试用例。

Lef*_*une 6

您可以通过让多个线程执行该方法然后断言结果是您所期望的来测试这一点。我怀疑这将是多么有效和可靠。众所周知,多线程代码很难测试,这主要归结为精心设计。我肯定会建议添加测试,以断言您希望通过 synchronized 实现的方法实际上具有 synchronized 修饰符。请参阅以下两种方法的示例:

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.junit.Test;

public class SyncTest {
  private final static int NUM_THREADS = 10;
  private final static int NUM_ITERATIONS = 1000;

  @Test
  public void testSynchronized() throws InterruptedException {
    // This test will likely perform differently on different platforms.
    ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
    final Counter sync = new Counter();
    final Counter notSync = new Counter();

    for (int i = 0; i < NUM_THREADS; i++) {
      executor.submit(new Runnable() {
        @Override
        public void run() {
          for (int i = 0; i < NUM_ITERATIONS; i++) {
            sync.incSync();
            notSync.inc();
          }
        }
      });
    }

    executor.shutdown();
    executor.awaitTermination(5, TimeUnit.SECONDS);
    assertThat(sync.getValue(), is(NUM_THREADS * NUM_ITERATIONS));
    assertThat(notSync.getValue(), is(not(NUM_THREADS * NUM_ITERATIONS)));
  }

  @Test
  public void methodIncSyncHasSynchronizedModifier() throws Exception {
    Method m = Counter.class.getMethod("incSync");
    assertThat(Modifier.isSynchronized(m.getModifiers()), is(true)); 
  }

  private static class Counter {
    private int value = 0;

    public synchronized void incSync() {
      value++;
    }

    public void inc() {
      value++;
    }

    public int getValue() {
      return value;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)