java – 测试方法是否以同步方式运行

以下代码是一个概述本单元测试目标的片段.下面演示了createFile只执行一个已知为线程安全操作的任务.

因此,这个想法更多地围绕着测试而不是实际操作;为了证明一个线程安全方法的行为,它以一种我们已经在历史上已经证明的方式运行.

public static final synchronized void createFile(final File file) throws IOException {
    file.createNewFile();
}

@Test
public void testCreateFileThreadSafety() throws Exception {
    for (int i = 1; i < 50; i++) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    createFile(new File(i+".txt"));
                    new File(i+".txt").delete();
                } catch (IOException ex) {
                   System.out.println(ex.getMessage());
                }
            }
        }).start();
        assertTrue(file.getParentFile().listFiles().length == 0);
    }
}

编辑:

现在发生了什么:线程被创建,文件被创建,文件被删除,线程死亡,断言证明什么都没有,并重复

期望的是:线程应该全部启动并且断言应该确保一次只创建一个文件并且其他线程正在等待,而不是执行该方法

双编辑:

我真正需要的是上述单元测试的重构,以便它做它应该做的事情(如上所述)

最佳答案 当然,对于这个非常简单的用例,它非常愚蠢,因为synchronized关键字就在那里.但一般来说,如果你想测试一个方法是否永远不会被同时调用,你可以抛出这个:

static AtomicInteger c = new AtomicInteger();

public void knownNonThreadSafeMethod(final File file) throws IOException {
    int t = c.incrementAndGet();
    doSomething();   
    Thread.yield(); //try to force race conditions, remove in prod
    assert t == c.intValue();
}

如果你使用一个简单的int i.s.o. AtomicInteger,编译器优化将删除断言.

static int c = 0;

public void knownNonThreadSafeMethod(final File file) throws IOException {
    int t = ++c;
    doSomething();   
    assert t == c; //smart-ass compiler will optimize to 'true'
}

使用AtomicInteger,可以保证在所有CPU和所有线程上同步该值,从而您将检测到任何并发访问.

我知道它不是在JUnit测试中,但我找不到任何非侵入性的方法来解决这个问题.也许你可以通过AspectJ注入它?

点赞