विषय के साथ विफल
मैं कुछ कोड है कि निश्चित रूप से सुरक्षित थ्रेड नहीं है:परीक्षण धागा सुरक्षा स्पॉक
public class ExampleLoader
{
private List<String> strings;
protected List<String> loadStrings()
{
return Arrays.asList("Hello", "World", "Sup");
}
public List<String> getStrings()
{
if (strings == null)
{
strings = loadStrings();
}
return strings;
}
}
एकाधिक धागे getStrings()
एक साथ null
रूप strings
देखने के लिए उम्मीद कर रहे हैं, और इस तरह loadStrings()
तक पहुँचने (जो एक महंगा ऑपरेशन है) कई बार ट्रिगर किया जाता है।
समस्या
मैं कोड धागा सुरक्षित बनाना चाहते थे, और दुनिया के एक अच्छे नागरिक के रूप में मैं एक असफल स्पॉक कल्पना पहले लिखा था:
def "getStrings is thread safe"() {
given:
def loader = Spy(ExampleLoader)
def threads = (0..<10).collect { new Thread({ loader.getStrings() })}
when:
threads.each { it.start() }
threads.each { it.join() }
then:
1 * loader.loadStrings()
}
ऊपर कोड बनाता है और 10 धागे शुरू होता है कि प्रत्येक getStrings()
पर कॉल करता है। फिर यह दावा करता है कि loadStrings()
केवल तभी बुलाया गया जब सभी धागे किए जाते हैं।
मुझे उम्मीद है कि यह असफल हो जाएगा। हालांकि, यह लगातार गुजरता है। क्या?
System.out.println
और अन्य उबाऊ चीजों से जुड़े एक डिबगिंग सत्र के बाद, मैंने पाया कि धागे वास्तव में असीमित हैं: उनके run()
विधियों को एक यादृच्छिक क्रम में मुद्रित किया गया है। हालांकि, getStrings()
तक पहुंचने वाला पहला धागा हमेशा धागा loadStrings()
पर कॉल करने के लिए होगा।
@Test
public void getStringsIsThreadSafe() throws Exception
{
// given
ExampleLoader loader = Mockito.spy(ExampleLoader.class);
List<Thread> threads = IntStream.range(0, 10)
.mapToObj(index -> new Thread(loader::getStrings))
.collect(Collectors.toList());
// when
threads.forEach(Thread::start);
threads.forEach(thread -> {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// then
Mockito.verify(loader, Mockito.times(1))
.loadStrings();
}
यह परीक्षण लगातार विफल रहता है कई कॉल की वजह से loadStrings()
लिए, के रूप में:
अजीब हिस्सा काफी कुछ समय बिताया डिबगिंग के बाद
निराश, मैं एक ही परीक्षण फिर से JUnit 4 और Mockito के साथ लिखा था अपेक्षित था।
सवाल
क्यों स्पॉक परीक्षण लगातार पारित होता है, और मैं स्पॉक के साथ इस परीक्षण के बारे में कैसे जाना होगा?
कोड के लिए परीक्षा लिखने के लिए कोड की मूल भाषा की तुलना में कभी भी कुछ भी क्यों उपयोग करना चाहेंगे? जैसा कि आप स्वयं पाते हैं, यह एक दुःस्वप्न डीबगिंग करता है। इस तथ्य के अलावा कि भाषा आगे बढ़ सकती है और इतनी प्यारी ढांचा पीछे रहती है। –
@OlegSklyar मुझे स्पार्क/ग्रोवी को अधिकांश जावा कोड को टेर्स और त्वरित तरीके से परीक्षण करने के लिए एक शानदार टूल मिल गया है। मुझे लगता है कि समस्या यहां स्पॉक फ्रेमवर्क के कार्यान्वयन के साथ है, क्योंकि ग्रोवी जावा बाइटकोड में संकलित है और इसके साथ जावा डीबगर का उपयोग करना काफी आसान है। साथ ही, यह एक समस्या की स्थिति में सामने आने वाली किसी समस्या का एक संक्षिप्त उदाहरण है- मैं न तो स्पॉक/ग्रोवी को खो सकता हूं और न ही जावा से मुख्य कोड बेस माइग्रेट कर सकता हूं। –
दुर्भाग्यवश मेरे पास आपके मूल प्रश्न का उत्तर नहीं है, इसलिए मेरे लिए यह एक दार्शनिक चर्चा है ... लेकिन किसी और ढांचे की शुरूआत जटिलता को बढ़ाती है। उस जटिलता ने अब आपको काट दिया है। मेरा मानना है कि जब आप कोड को दोबारा करने का फैसला करते हैं तो सुंदर ढांचा सभी परीक्षणों को भी दोबारा कर देगा। निश्चित रूप से यह नहीं होगा। हालांकि स्वयं निर्मित किए गए मुझे जावा परियोजनाओं में से एक में समान ढांचे से निपटना पड़ा: जब तक हमने जावा टेस्ट-बेस लाइब्रेरी नहीं लिखी, तब तक परीक्षणों को ठीक करने या संशोधित करने के लिए दुःस्वप्न था। अब सभी परीक्षण समझदार और अपवर्तक हैं। –