There are other questions about this issue, but I'm trying to figure how to approach unit testing something like this:
public class Semaphore extends Lock {
private AtomicInteger semaphore = new AtomicInteger(0);
public synchronized boolean available() {
return semaphore.intValue() == 0;
}
public synchronized void acquire() {
semaphore.incrementAndGet();
}
public synchronized void release() {
semaphore.decrementAndGet();
}
}
This is my homespun locking mechanism (just for learning purposes). How would I test the thread safety of this? I know that there are no guarantees when it comes to unit testing concurrent code, but how would I even go about writing a unit test that ATTEMPTS to test the obvious invariants inherent in this locking mechanism?
Process for concurrency testing :Create high and low-level scenarios for concurrent testing. Keep ready different platforms for testing. Creating the environment for testing. Now, two or more testers can start the test by performing the same task at the same times.
Arrange/Act/Assert (AAA) is a pattern for organizing unit tests. It breaks tests down into three clear and distinct steps: Arrange: Perform the setup and initialization required for the test. Act: Take action(s) required for the test. Assert: Verify the outcome(s) of the test.
Once parallel test execution property is enabled, the JUnit Jupiter engine will execute tests in parallel according to the provided configuration with declared synchronization mechanisms.
It breaks each test down into three parts – Arrange, Act, and Assert – where each part is a step leading to the next. The arrange step sets up the test's input values. The act step prompts the primary function being tested. And finally, the assert step verifies that the output of the function is what was expected.
I guess I'll answer my own question since I did some research. There's a great framework called MultithreadedTC. It allows you to set up tests like so:
public class SafeSemaphoreTest extends MultithreadedTestCase {
private SafeSemaphore semaphore;
AtomicInteger ai = new AtomicInteger(0);
@Override
public void initialize() {
semaphore = new SafeSemaphore();
}
public void thread1() throws InterruptedException {
assertTick(0);
semaphore.acquire();
waitForTick(2);
assertTick(2);
semaphore.acquire();
assertEquals(semaphore.getValue(), 2);
assertEquals(semaphore.getValue()==3, false);
semaphore.release();
semaphore.release();
}
public void thread2() throws InterruptedException {
waitForTick(1);
assertTick(1);
assertEquals(semaphore.available(), false);
waitForTick(3);
assertTick(3);
assertEquals(semaphore.available(), true);
}
}
where the waitForTick(int) calls make the current Thread block until the tick is reached. There was even some development to make this a bit more modern for better JUnit integration: http://janvanbesien.blogspot.com/2009/06/modernizing-multithreadedtc-junit-4.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With