【问题标题】:How to unit test synchronized code如何对同步代码进行单元测试
【发布时间】:2010-05-13 09:28:25
【问题描述】:

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

【问题讨论】:

标签: java unit-testing synchronization junit


【解决方案1】:

如果你对使用 JUnit 不是太讲究,那么你可以使用 TestNG 框架。它们具有多线程支持。

【讨论】:

    【解决方案2】:

    作为测试框架的替代方案(或在 JUnit 之上的额外扩展,如果您正在使用它)只是一些普通的旧代码:

    • 创建多个线程并将它们应用于此例程。
    • 遍历线程并测试每个线程,直到找出谁是领导者。
    • 将不同的环境更改(包括时间流逝)应用到程序的状态并重新进行测试。领导者还是领导者吗?
    • 现在,强制领导退位(杀死那个线程或其他东西)。另一个线程接管了吗?

    【讨论】:

      【解决方案3】:

      对于 JUnit,有来自 junit-toolboxMultithreadingTester

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-21
        • 2010-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多