Skip to content

Commit 829df03

Browse files
committed
Intermittent failure was due to Thread.sleep in the code. While performing unit test cases there was race condition between two threads, so it was not guaranteed to work every time. Used an interface DelayProvider for simulating delay, and while unit testing fake delay provider is used that eradicates the use of Threads in unit test cases, which is not a good practice.
1 parent db33cc5 commit 829df03

File tree

3 files changed

+59
-28
lines changed

3 files changed

+59
-28
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.iluwatar.balking;
2+
3+
import java.util.concurrent.TimeUnit;
4+
5+
/**
6+
* An interface to simulate delay while executing some work.
7+
*/
8+
public interface DelayProvider {
9+
void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task);
10+
}

balking/src/main/java/com/iluwatar/balking/WashingMachine.java

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,38 @@
2525
import org.slf4j.Logger;
2626
import org.slf4j.LoggerFactory;
2727

28+
import java.util.concurrent.TimeUnit;
29+
2830
/**
2931
* Washing machine class
3032
*/
3133
public class WashingMachine {
3234

3335
private static final Logger LOGGER = LoggerFactory.getLogger(WashingMachine.class);
34-
36+
private final DelayProvider delayProvider;
3537
private WashingMachineState washingMachineState;
3638

39+
/**
40+
* Creates a new instance of WashingMachine
41+
*/
3742
public WashingMachine() {
38-
washingMachineState = WashingMachineState.ENABLED;
43+
this((interval, timeUnit, task) -> {
44+
try {
45+
Thread.sleep(timeUnit.toMillis(interval));
46+
} catch (InterruptedException ie) {
47+
ie.printStackTrace();
48+
}
49+
task.run();
50+
});
51+
}
52+
53+
/**
54+
* Creates a new instance of WashingMachine using provided delayProvider. This constructor is used only for
55+
* unit testing purposes.
56+
*/
57+
public WashingMachine(DelayProvider delayProvider) {
58+
this.delayProvider = delayProvider;
59+
this.washingMachineState = WashingMachineState.ENABLED;
3960
}
4061

4162
public WashingMachineState getWashingMachineState() {
@@ -56,12 +77,8 @@ public void wash() {
5677
washingMachineState = WashingMachineState.WASHING;
5778
}
5879
LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
59-
try {
60-
Thread.sleep(50);
61-
} catch (InterruptedException ie) {
62-
ie.printStackTrace();
63-
}
64-
endOfWashing();
80+
81+
this.delayProvider.executeAfterDelay(50, TimeUnit.MILLISECONDS, this::endOfWashing);
6582
}
6683

6784
/**

balking/src/test/java/com/iluwatar/balking/WashingMachineTest.java

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,8 @@
2222
*/
2323
package com.iluwatar.balking;
2424

25-
import org.junit.jupiter.api.Disabled;
2625
import org.junit.jupiter.api.Test;
2726

28-
import java.util.concurrent.ExecutorService;
29-
import java.util.concurrent.Executors;
3027
import java.util.concurrent.TimeUnit;
3128

3229
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -36,32 +33,39 @@
3633
*/
3734
public class WashingMachineTest {
3835

39-
private volatile WashingMachineState machineStateGlobal;
36+
private FakeDelayProvider fakeDelayProvider = new FakeDelayProvider();
4037

41-
@Disabled
4238
@Test
43-
public void wash() throws Exception {
44-
WashingMachine washingMachine = new WashingMachine();
45-
ExecutorService executorService = Executors.newFixedThreadPool(2);
46-
executorService.execute(washingMachine::wash);
47-
executorService.execute(() -> {
48-
washingMachine.wash();
49-
machineStateGlobal = washingMachine.getWashingMachineState();
50-
});
51-
executorService.shutdown();
52-
try {
53-
executorService.awaitTermination(10, TimeUnit.SECONDS);
54-
} catch (InterruptedException ie) {
55-
ie.printStackTrace();
56-
}
39+
public void wash() {
40+
WashingMachine washingMachine = new WashingMachine(fakeDelayProvider);
41+
42+
washingMachine.wash();
43+
washingMachine.wash();
44+
45+
WashingMachineState machineStateGlobal = washingMachine.getWashingMachineState();
46+
47+
fakeDelayProvider.task.run();
48+
49+
// washing machine remains in washing state
5750
assertEquals(WashingMachineState.WASHING, machineStateGlobal);
51+
52+
// washing machine goes back to enabled state
53+
assertEquals(WashingMachineState.ENABLED, washingMachine.getWashingMachineState());
5854
}
5955

6056
@Test
61-
public void endOfWashing() throws Exception {
57+
public void endOfWashing() {
6258
WashingMachine washingMachine = new WashingMachine();
6359
washingMachine.wash();
6460
assertEquals(WashingMachineState.ENABLED, washingMachine.getWashingMachineState());
6561
}
6662

63+
private class FakeDelayProvider implements DelayProvider {
64+
private Runnable task;
65+
66+
@Override
67+
public void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task) {
68+
this.task = task;
69+
}
70+
}
6771
}

0 commit comments

Comments
 (0)