2014-12-30 2 views
0

테스트 개발을 가속화하기 위해 테스트 작성자에게 '프레임 워크'를 제공하기 위해 testNG를 사용하고 있습니다. 이것을 달성하기 위해 나는 추상적 인 테스트 클래스를 가지고있다. 모든 서면 테스트는이 테스트 클래스에서 파생됩니다. 이 테스트는 testNG에 의해 병렬로 실행될 수 있습니다. 이제는 @BeforeClass 메서드에서 때때로 간단한 'getClass(). getName()'메서드가 병렬로 실행될 때 null을 반환한다는 것을 알았습니다. 나는에 나중에 그 값을 사용 (
의 ThreadLocal 클래스 이름은 정적이어야 @getClass(). getName()은 null을 반환합니다.

... 
Starting test com.mycompany.testsets.LocalTestSet$IntegrationTest3 
Starting test null 
Starting test com.mycompany.testsets.LocalTestSet$IntegrationTest1 
... 

일부 발언 : 나는 병렬 테스트의 무리에 대해이 작업을 실행하면

private static ThreadLocal<String> className; 

@BeforeClass 
public void init(){ 
     initName(); 
     className.set(getClass().getName());    
     log("Starting test " + className.get()); 
} 

private synchronized void initName(){ 
    if(className == null){ 
     className = new ThreadLocal<>(); 
    } 
} 

나는이 출력을 얻을 Dataprovider)
무작위로 발생하고 모든 테스트에서 발생할 수 있기 때문에 스레드 보안 문제로 간주되지만 어떻게 'getClass(). getName()'스레드를 더 안전하게 만들 수 있는지 알지 못합니다.

감사합니다.

답변

0

initName에서 지연 초기화를 건너 뜁니다. 스레드로부터 안전하지는 않습니다. 대신

는 직접 ThreadLocal 필드를 초기화 (도 유의 final) :

private static final ThreadLocal<String> className = new ThreadLocal<>(); 

(현재 클래스의 이름을 유지하기 위해 ThreadLocal 필요합니까 왜 당신은 쉽게 그것을 얻을 수 Btw는 .:? 매번 getClass().getName()으로 전화하여 원하는 때마다).

+0

정적 인 @dataprovider 메서드 안에 데이터를 동적으로 생성하고이 정적 메서드 내부에있는 하위 클래스의 클래스 이름을 가져와야하기 때문에 필요합니다. 이제는 더 나은 접근법이 아마도 testNG 팩토리를 사용하는 것이라는 것을 알았지 만, 너무 늦어서 해결할 필요가 있습니다. 나는 지금 당신의 'non-lazy'초기화를 시도 할 것이다. – MajorT

+0

마지막의 read-before는 실제로 트릭을했다. :) 고마워요! – MajorT

2

경쟁 조건이있는 것 같습니다. 한 스레드가 다른 스레드가 log을 호출하기 전에 initName을 호출하면 새로운 ThreadLocal은 값을 가지지 않습니다. null을 반환합니다.

null의 수표를 initName 내에 보호하는 스레드 안전 장치가 없습니다.

+0

initName()을 입력하는 첫 번째 스레드는 동기화 된 이후 다른 스레드를 차단한다고 가정했습니다. 그 가정이 잘못 되었습니까? 그렇다면 다른 스레드를 차단하는 적절한 방법은 무엇입니까? – MajorT

+0

@MajorT 여러분의'initName' 메쏘드는 클래스가 아닌 인스턴스에서 동기화합니다. 따라서 다른 인스턴스에서 호출되는'initName'은 병렬로 실행됩니다. – isnot2bad

관련 문제