代码之家  ›  专栏  ›  技术社区  ›  HipsterZipster

如何编写“InterruptedException”的单元测试

  •  10
  • HipsterZipster  · 技术社区  · 15 年前

    在尝试100%的代码覆盖率时,我遇到了这样一种情况,即我需要对捕获错误的代码块进行单元测试 InterruptedException

    private final LinkedBlockingQueue<ExampleMessage> m_Queue;  
    
    public void addMessage(ExampleMessage hm) {  
        if( hm!=null){
            try {
                m_Queue.put(hm);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    5 回复  |  直到 10 年前
        1
  •  19
  •   erickson    15 年前

    就在调用之前 addMessage() Thread.currentThread().interrupt() . 这将在线程上设置“中断”状态标志。

    put() 是在一个 LinkedBlockingQueue ,安 InterruptedException 即使不需要等待 put (锁是不争用的)。

    顺便说一句,一些达到100%覆盖率的努力是适得其反的,实际上会降低代码的质量。

        2
  •  14
  •   timbre timbre    7 年前

    使用像Easymock这样的模拟库并注入一个模拟LinkedBlockingQueue

    @Test(expected=InterruptedException.class)
    public void testInterruptedException() {
        LinkedBlockingQueue queue = EasyMock.createMock(LinkedBlockingQueue.class);
        ExampleMessage message = new ExampleMessage();
        queue.put(message);
        EasyMock.expectLastCall.andThrow(new InterruptedException()); 
        replay(queue);
        someObject.setQueue(queue);
        someObject.addMessage(msg);
    }
    
        3
  •  3
  •   ixi    7 年前

    如上所述,只要利用 Thread.currentThread().interrupt() 如果你抓住了 InterruptedException 不会再重复了。

    Assertions.assertThat(Thread.interrupted()).isTrue(); . 它检查线程是否被中断,并清除中断标志,这样它就不会破坏其他测试、代码覆盖率或下面的任何内容。

        4
  •  1
  •   Michal Kordas FrantiÅ¡ek Hartman    8 年前

    另一种选择是授权处理 InterruptedException 番石榴 Uninterruptibles ,因此您无需为此编写和测试自定义代码:

    import static com.google.common.util.concurrent.Uninterruptibles.putUninterruptibly;
    
    private final LinkedBlockingQueue<ExampleMessage> queue;  
    
    public void addMessage(ExampleMessage message) {  
        putUninterruptibly(queue, message);
    }
    
        5
  •  0
  •   wtsolid    7 年前

    ThreadFactory中重写方法“newThread”的演示代码部分:

    ThreadFactory customThreadfactory new ThreadFactory() {
    
                public Thread newThread(Runnable runnable) {
                    final Thread thread = new Thread(runnable);
                    if (namePrefix != null) {
                        thread.setName(namePrefix + "-" + count.getAndIncrement());
                    }
                    if (daemon != null) {
                        thread.setDaemon(daemon);
                    }
                    if (priority != null) {
                        thread.setPriority(priority);
                    }
    
                    scheduledExecutorService.schedule(new Callable<String>() {
                        public String call() throws Exception {
                            System.out.println("Executed!");
                            thread.interrupt();
                            return "Called!";
    
                        }
                    },
                    5,
                    TimeUnit.SECONDS);
    
                    return thread;
                }
            }
    

    然后您可以使用下面的命令来构造executorservice实例:

    ExecutorService executorService = Executors.newFixedThreadPool(3,
            customThreadfactory);
    

    然后在5秒钟之后,一个中断信号将被发送到线程,每个线程在服务中中断一次。

        6
  •  0
  •   kap    4 年前

    问题中的示例代码可以通过调用 Thread.currentThread().interrupt() . 然而,除了上述问题之外,还有各种方法重置了 interrupted 旗帜。例如,这里有一个广泛的列表: https://stackoverflow.com/a/12339487/2952093

    假设按以下方式实现的等待应进行测试:

    try {
      TimeUnit.SECONDS.sleep(10);
    } catch (InterruptedException ex) {
        // Set the interrupt flag, this is best practice for library code
        Thread.currentThread().interrupt();
        throw new RuntimeException(ex);
    }
    

    打电话给 Thread.sleep 自身清除 打断

    AtomicBoolean threadInterrupted = new AtomicBoolean(false);
    Runnable toBeInterrupted = () -> {
        try {
            methodUnderTest();
        } catch (RuntimeException unused) {
            // Expected exception
            threadInterrupted.set(true);
        }
    };
    
    // Execute the in an operation test thread
    Thread testThread = new Thread(toBeInterrupted);
    testThread.start();
    
    // When the test thread is waiting, interrupt
    while (!threadInterrupted.get()) {
        if (testThread.getState() == Thread.State.TIMED_WAITING) {
            testThread.interrupt();
        }
    }
    
    // Assert that the interrupted state is re-set after catching the exception
    // Must be happening before thread is joined, as this will clear the flag
    assertThat(testThread.isInterrupted(), is(true));
    testThread.join();