如何对同步代码进行单元测试

问题描述:

我是Java和junit的新手。我有以下代码,我想测试。如果您能发送关于测试它的最佳方式的想法,请多加谅解。如何对同步代码进行单元测试

基本上,下面的代码是关于从一个集群中选举一个领导者的。领导者持有对共享缓存的锁定,并且领导者的服务可以恢复并处理,如果它以某种方式丢失了缓存上的锁定。

如何确保领导者/线程仍然保持缓存中的锁定,并且另一个线程无法在第一次执行时恢复其服务?

public interface ContinuousService { 

public void resume(); 
public void pause(); 
} 


public abstract class ClusterServiceManager { 
private volatile boolean leader = false; 
private volatile boolean electable = true; 
private List<ContinuousService> services; 

protected synchronized void onElected() { 
    if (!leader) { 
     for (ContinuousService service : services) { 
      service.resume(); 
     } 
     leader = true; 
    } 
} 

protected synchronized void onDeposed() { 
    if (leader) { 
     for (ContinuousService service : services) { 
      service.pause(); 
     } 
     leader = false; 
    } 
} 

public void setServices(List<ContinuousService> services) { 
    this.services = services; 
} 

@ManagedAttribute 
public boolean isElectable() { 
    return electable; 
} 

@ManagedAttribute 
public boolean isLeader() { 
    return leader; 
} 



public class TangosolLeaderElector extends ClusterServiceManager implements Runnable { 
private static final Logger log = LoggerFactory.getLogger(TangosolLeaderElector.class); 
private String election; 
private long electionWaitTime= 5000L; 

private NamedCache cache; 

public void start() { 
    log.info("Starting LeaderElector ({})",election); 
    Thread t = new Thread(this, "LeaderElector ("+election+")"); 
    t.setDaemon(true); 
    t.start(); 
} 

public void run() { 
    // Give the connection a chance to start itself up 
    try { 
     Thread.sleep(1000); 
    } catch (InterruptedException e) {} 

    boolean wasElectable = !isElectable(); 
    while (true) { 
     if (isElectable()) { 
      if (!wasElectable) { 
       log.info("Leadership requested on election: {}",election); 
       wasElectable = isElectable(); 
      } 
      boolean elected = false; 
      try { 
       // Try and get the lock on the LeaderElectorCache for the current election 
       if (!cache.lock(election, electionWaitTime)) { 
        // We didn't get the lock. cycle round again. 
        // This code to ensure we check the electable flag every now & then 
        continue; 
       } 
       elected = true; 
       log.info("Leadership taken on election: {}",election); 
       onElected(); 

       // Wait here until the services fail in some way. 
       while (true) { 
        try { 
         Thread.sleep(electionWaitTime); 
        } catch (InterruptedException e) {} 
        if (!cache.lock(election, 0)) { 
         log.warn("Cache lock no longer held for election: {}", election); 
         break; 
        } else if (!isElectable()) { 
         log.warn("Node is no longer electable for election: {}", election); 
         break; 
        } 
        // We're fine - loop round and go back to sleep. 
       } 
      } catch (Exception e) { 
       if (log.isErrorEnabled()) { 
        log.error("Leadership election " + election + " failed (try bfmq logs for details)", e); 
       } 
      } finally { 
       if (elected) { 
        cache.unlock(election); 
        log.info("Leadership resigned on election: {}",election); 
        onDeposed(); 
       } 
       // On deposition, do not try and get re-elected for at least the standard wait time. 
       try { Thread.sleep(electionWaitTime); } catch (InterruptedException e) {} 
      } 
     } else { 
      // Not electable - wait a bit and check again. 
      if (wasElectable) { 
       log.info("Leadership NOT requested on election ({}) - node not electable",election); 
       wasElectable = isElectable(); 
      } 
      try { 
       Thread.sleep(electionWaitTime); 
      } catch (InterruptedException e) {} 
     } 
    } 
} 

public void setElection(String election) { 
    this.election = election; 
} 

@ManagedAttribute 
public String getElection() { 
    return election; 
} 

public void setNamedCache(NamedCache nc) { 
    this.cache = nc; 
} 
+0

http://today.java.net/article/2003/07/12/multithreaded-tests-junit http://www.junit.org/node/54 – Bozho 2010-05-13 09:41:38

作为替代测试框架(或JUnit的顶部额外的扩展,如果你正在使用的)只是一些普通的旧代码:

  • 创建多个线程,并将其应用到这个程序。
  • 循环穿过线程并测试每个线程,直到找出谁是领导者。
  • 将不同的环境变化(包括时间流逝)应用于程序状态并重做测试。领导者仍然是领导者吗?
  • 现在,强迫领导者放弃(杀死那个线程或其他东西)。另一个线程接管了吗?

如果您对使用JUnit不太具体,那么您可以使用TestNG框架。他们有多线程支持。

对于JUnit,有MultithreadingTesterjunit-toolbox