java如何应用同步?
我有UI自动化测试。测试涉及三个实体:
数据对象类-要在表单中填写的数据。在此,页面上的每个表单可以由不同的数据对象表示
Helper类-在第页的表单中填充数据
测试类-它使用数据对象和助手类来执行测试
以下是测试的简化版本-
public class ParallelDataObject {
HelperClass helperClass = new HelperClass();
Data data;
@BeforeMethod
public void setTestData() {
data = new Data();
helperClass.setData(data);
}
@Test
public void passM1() {
helperClass.verifyFlag();
}
@Test
public void failM2() {
data.setFlag(false);
helperClass.setData(data);
helperClass.verifyFlag();
}
@Test
public void passM3() {
helperClass.verifyFlag();
}
@Test
public void failM4() {
data.setFlag(false);
helperClass.setData(data);
helperClass.verifyFlag();
}
}
class HelperClass {
Data data;
public void setData(Data data) {
synchronized (data) {
this.data = data;
}
}
public void verifyFlag() {
synchronized (data) {
assert data.getFlag();
}
}
}
class Data {
private boolean flag;
public Data() {
flag = true;
}
public Data setFlag(boolean flag) {
synchronized (this) {
this.flag = flag;
return this;
}
}
public boolean getFlag() {
synchronized (this) {
return flag;
}
}
当并行执行方法时,我遇到了奇怪的结果,因为数据不是线程安全的。然后我合并了同步块,但是我遇到了奇怪的结果。 我肯定我搞砸了这里应该如何使用同步。有什么见解吗
我又做了一次运动。我设置了与第一个测试类完全相同的另一个测试类。我从helper和data类中删除了所有同步。当我并行运行类(而不是方法)时。测试结果与预期一致。为什么我在并行执行类时不运行并发性,即使它们使用相同的帮助器类和数据对象
# 1 楼答案
考虑使用^{} 。这样,每个线程都有自己的
HelperClass
副本。请注意,同步不同的方法不会给您带来任何好处—在一个测试(在一个线程中)中所做的更改可以被其他测试看到其他改进:
passM3
和failM4
是多余的HelperClass
需要一个Data
实例才能工作,所以它应该使用构造函数依赖项声明它使用时:
包装整个方法体,考虑在方法声明中使用^ {< CD7>}关键字(更可读)。
不再需要与
ThreadLocal
同步测试无状态
@gpeche提出了一个很好的建议,即测试应该是独立的。不幸的是(为什么,哦为什么!)JUnit为所有测试方法的执行重用相同的测试用例类实例(
ParallelDataObject
)。这意味着将任何有状态对象分配给测试用例类字段是危险的,必须避免在这种特殊情况下,OP必须在每个测试方法中创建一个新的HelperClass实例(事实上,这不是一个坏主意):
# 2 楼答案
HelperClass
和Data
是线程安全的问题是您的一些测试方法执行了多个操作。而且,只要测试方法中的操作序列不同步,它就不是原子的
例如,在
failM4
执行期间helperClass
的状态可能会被其他线程修改我建议您不要在测试方法之间使用共享状态,因为同步将抵消并发测试执行的优势