Рассмотрите возможность использования ThreadLocal
. Таким образом, каждый поток имеет свою собственную копию HelperClass
. Обратите внимание, что синхронизация отдельных методов ничего не даст - изменения, внесенные в одном тесте (в одном потоке), видны в других тестах
class ParallelDataObject {
private final ThreadLocal<HelperClass> helperClassThreadLocal = new ThreadLocal<HelperClass>() {
@Override
protected HelperClass initialValue() {
return new HelperClass(new Data());
}
};
private HelperClass helperClass() {
return helperClassThreadLocal.get();
}
@Test
public void passM1() {
helperClass().verifyFlag();
}
@Test
public void failM2() {
helperClass().getData().setFlag(false);
helperClass().verifyFlag();
}
}
class HelperClass {
private final Data data;
public HelperClass(Data data) {
this.data = data;
}
public Data getData() {
return data;
}
public void verifyFlag() {
assert data.getFlag();
}
}
class Data {
private boolean flag = true;
public Data setFlag(boolean flag) {
this.flag = flag;
return this;
}
public boolean getFlag() {
return flag;
}
}
Другие улучшения:
passM3
и failM4
были лишними
- , поскольку
HelperClass
для работы требуется экземпляр Data
, он должен объявить его с помощью зависимости конструктора
при использовании:
synchronized(this)
Оборачивая все тело метода, рассмотрите возможность использования ключевого слова synchronized
в объявлении метода (более читабельно).
синхронизация больше не требуется с ThreadLocal
s
Проверка безгражданства
@ gpeche дает хорошее предположение, что тесты должны быть независимыми. К сожалению (почему, о, почему !?) JUnit повторно использует один и тот же экземпляр класса тестового примера (ParallelDataObject
в этом случае) для выполнения всех тестовых методов. Это означает, что назначение любых объектов с состоянием для полей класса тестового случая опасно, и его следует избегать.
В этом конкретном случае OP должен был бы создать новый экземпляр HelperClass в каждом методе тестирования (что, на самом деле, неплохая идея) :
class ParallelDataObject {
@Test
public void passM1() {
final HelperClass helperClass = new HelperClass(new Data());
helperClass.verifyFlag();
}
@Test
public void failM2() {
final Data data = new Data();
data.setFlag(false);
final HelperClass helperClass = new HelperClass(data);
helperClass.verifyFlag();
}
}