2010-05-13 101 views
9

我是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

回答

3

作爲替代測試框架(或JUnit的頂部額外的擴展,如果你正在使用的)只是一些普通的舊代碼:

  • 創建多個線程,並將其應用到這個程序。
  • 循環穿過線程並測試每個線程,直到找出誰是領導者。
  • 將不同的環境變化(包括時間流逝)應用於程序狀態並重做測試。領導者仍然是領導者嗎?
  • 現在,強迫領導者放棄(殺死那個線程或其他東西)。另一個線程接管了嗎?
4

如果您對使用JUnit不太具體,那麼您可以使用TestNG框架。他們有多線程支持。