java - 为什么这不起作用 - 使用 Junit 的参数化数据对同步方法进行单元测试?

标签 java multithreading unit-testing junit parameterized-unit-test

我正在尝试学习 JUnit 并希望将其扩展为以多线程方式进行测试。

我要测试的类是 PrimeNumberValidator。这只是测试传入的数字是否为素数。

package com;

public class PrimeNumberValidator {
    public Boolean validate(final Integer primeNumber) {
        System.out.println("Validating .............:" + primeNumber);
        for (int i = 2; i < (primeNumber / 2); i++) {
            if (primeNumber % i == 0) {
                return false;
            }
        }

        return true;
    }
}


PrimeNumberValidatorTest 是测试类。 2个测试数据是错误的,我故意这样做是为了测试失败。
测试方法 testPrimeNumberValidator 运行得很好。但是,多线程版本
testMultiThreadedPrimeNumberValidator 即使是错误的数据也总是说“通过”。
为什么会这样?
如何解决?

package com;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class PrimeNumberValidatorTest {
    private Integer primeNumber;
    private Boolean expectedValidation;
    private PrimeNumberValidator primeNumberValidator;

    @Before
    public void initialize() {
    primeNumberValidator = new PrimeNumberValidator();
    }

    // Each parameter should be placed as an argument here
    // Every time runner triggers, it will pass the arguments from parameters we defined
    public PrimeNumberValidatorTest(Integer primeNumber, Boolean expectedValidation) {
    this.primeNumber = primeNumber;
    this.expectedValidation = expectedValidation;
    }

    @Parameterized.Parameters
    public static Collection primeNumbers() {
    return Arrays.asList(new Object[][] {
        { 2, Boolean.FALSE},// 2 is prime so Test should fail
        { 6, Boolean.FALSE}, //is NOT prime so test should pass
        { 19, Boolean.TRUE},//is prime so test should pass
        { 22, Boolean.TRUE} //is NOT prime so test should fail
    });
    }

    // This test will run 4 times since we have 4 parameters defined
    @Test
    public void testPrimeNumberValidator() {
    assertEquals(expectedValidation, primeNumberValidator.validate(primeNumber));
    }

    @Test
    public void testMultiThreadedPrimeNumberValidator() {

    ExecutorService executor = Executors.newFixedThreadPool(100);
    executor.submit(new Runnable() {

        public void run() {
        for (int i = 0; i < 100; i++) {
            assertEquals(expectedValidation, primeNumberValidator.validate(primeNumber));
        }   
        }
    }); 
    }
}

引用
http://www.youtube.com/watch?v=wDN_EYUvUq0正如其中一篇文章所述
Weird problem using JUnit in multi-thread environment ,尝试如下。
抛出异常,但JUnit不报错:(

package com;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class PrimeNumberValidatorTest {
    volatile Exception exception;
    volatile Error error;

    private Integer primeNumber;
    private Boolean expectedValidation;
    private PrimeNumberValidator primeNumberValidator;

    @Before
    public void initialize() {
    primeNumberValidator = new PrimeNumberValidator();
    }

    // Each parameter should be placed as an argument here
    // Every time runner triggers, it will pass the arguments from parameters we defined
    public PrimeNumberValidatorTest(Integer primeNumber, Boolean expectedValidation) {
    this.primeNumber = primeNumber;
    this.expectedValidation = expectedValidation;
    }

    @Parameterized.Parameters
    public static Collection primeNumbers() {
    return Arrays.asList(new Object[][] {
        { 2, Boolean.FALSE},// 2 is prime so Test should fail
        { 6, Boolean.FALSE}, //is NOT prime so test should pass
        { 19, Boolean.TRUE},//is prime so test should pass
        { 22, Boolean.TRUE} //is NOT prime so test should fail
    });
    }

    // This test will run 4 times since we have 4 parameters defined
    @Test
    @Ignore
    public void testPrimeNumberValidator() {
    assertEquals(expectedValidation, primeNumberValidator.validate(primeNumber));
    }

    @Test
    public void testMultiThreadedPrimeNumberValidator() {

    ExecutorService executor = Executors.newFixedThreadPool(100);
    executor.submit(new Runnable() {

        public void run() {
        for (int i = 0; i < 1; i++) {
            try{
                assertEquals(expectedValidation, primeNumberValidator.validate(primeNumber));
            }catch(Error e){
                System.out.println("error thrown :" + e);
                error =e;
            }catch(Exception e){
                exception=e;
                System.out.println("exception thrown :" + e);
            }
        }   
        }
    }); 
    }

    @After
    public void runAfterEveryTest() throws Exception{
    if(null != error){
        System.out.println("runAfterEveryTest throwing error...............");
        throw error;
    }
    if(null != exception){
        System.out.println("runAfterEveryTest throwing exception...............");
        throw exception;
    }
    }
}

最佳答案

多线程总是pass的原因如下:

  • 首先,测试方法不会等待多个线程完成,因此 @Test 方法在报告任何错误之前退出
  • 其次,测试的工作方式是 assert 方法抛出异常。 JUnit 框架通过包装 @Test 方法捕获此异常,如果抛出意外异常,则测试失败。但是,在多线程测试中,@Test 方法不会抛出任何异常,因为它们是在线程内抛出的,而测试方法不会对此进行任何检查。这部分的一种解决方案是使用 ErrorCollector

关于java - 为什么这不起作用 - 使用 Junit 的参数化数据对同步方法进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18890721/

相关文章:

java - @PostPersist 未调用...@PrePersist 是...为什么?

android - 从 Activity.onCreate() 创建永不消亡的线程

java - 首先在套件中运行的所有测试的 JUnit 参数方法,而不是在每个测试之前运行

unit-testing - 使用 TestNG 的动态测试套件

java - 如何将 Java MessageFormat 选择与 boolean 值一起使用?

java - 如何在Selenium 2的ChromeDriver中设置HTTP代理?

java - 为什么需要 "Storing a reference to it into a final field"和 "of a properly constructed object"才能安全地发布对象?

c - 树莓派多线程套接字问题C

c++ - TDD:给定 C++ 中的未定义行为,确定性地测试成员初始化

java - 如何使 SAXParser 忽略转义码