ฉันจะทดสอบหน่วยเรียนที่ต้องใช้บริการโทรทางเว็บได้อย่างไร


21

ฉันพยายามทดสอบคลาสที่เรียกบริการเว็บของ Hadoop รหัสมีรูปแบบค่อนข้างมาก:

method() {
    ...use Jersey client to create WebResource...
    ...make request...
    ...do something with response...
}

เช่นมีวิธีสร้างไดเรกทอรีวิธีสร้างโฟลเดอร์เป็นต้น

ระบุว่ารหัสนั้นเกี่ยวข้องกับบริการเว็บภายนอกที่ฉันไม่สามารถควบคุมได้ฉันจะทดสอบหน่วยนี้ได้อย่างไร ฉันสามารถลองและเยาะเย้ยไคลเอนต์บริการเว็บ / การตอบสนอง แต่นั่นทำลายแนวทางที่ฉันได้เห็นมากเมื่อเร็ว ๆ นี้: "อย่าเยาะเย้ยวัตถุที่คุณไม่ได้เป็นเจ้าของ" ฉันสามารถตั้งค่าการใช้บริการเว็บจำลองที่ยังคงเป็นการทดสอบหน่วยหรือว่าเป็นการทดสอบการรวมหรือไม่ เป็นไปไม่ได้หรือที่จะทำการทดสอบหน่วยในระดับต่ำนี้ผู้ประกอบการ TDD จะทำเช่นนี้ได้อย่างไร?


5
คุณเคยเห็นคำแนะนำเกี่ยวกับการไม่ล้อเลียนสิ่งที่คุณไม่ได้เป็นเจ้าของ ดูเหมือนจะเป็นเหตุผลใหญ่ว่าทำไมคุณควรล้อเลียนสิ่งต่าง ๆ ...
โธมัสโอเวนส์

1
ฉันอ่านมันในบล็อกจำนวนมากซึ่งหนึ่งในนั้นอ้างอิงถึงamazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/…ซึ่งฉันรู้ว่าเป็นหนังสือที่ได้รับการยกย่องเป็นอย่างมาก ( blog.8thlight com / eric-smith / 2011/10/27 / thats-not-yours.html , mockobjects.com/2007/04/test-smell-everything-is-mocked.html )
Chris Cooper

1
@ChrisCooper: ฉันขอชี้ให้เห็นว่าลิงก์ล่าสุดล้าสมัยมาก (ตั้งแต่ปี 2007) มีการเปลี่ยนแปลงมากมายตั้งแต่นั้นมา ฉันได้รับความรู้สึกจากการโพสต์ว่าการเยาะเย้ยเป็นเรื่องที่ยากขึ้นมากในตอนนั้นเมื่อคุณต้องใช้พฤติกรรมจริงแทนที่จะใช้เพียงกรอบการเยาะเย้ยหรือ metaprogramming เพื่อตั้งค่าผลตอบแทน ...
c_maker

คำตอบ:


41

ในความคิดของฉันคุณควรเยาะเย้ยเว็บเซอร์โทรถ้านี่คือการทดสอบหน่วยซึ่งตรงข้ามกับการทดสอบการรวม

การทดสอบหน่วยของคุณไม่ควรทดสอบว่าการบริการเว็บภายนอกทำงานได้หรือไม่หรือการรวมระบบของคุณถูกต้องหรือไม่ โดยไม่ได้รับความเชื่อมั่นมากเกินไปเกี่ยวกับ TDD โปรดทราบว่าผลข้างเคียงของการเปลี่ยนการทดสอบหน่วยของคุณเป็นการทดสอบการรวมเข้าด้วยกันคือมีแนวโน้มว่าจะทำงานช้าลงและคุณต้องการการทดสอบหน่วยที่รวดเร็ว

นอกจากนี้ถ้าเว็บเซอร์หยุดทำงานชั่วคราวหรือทำงานไม่ถูกต้องสิ่งนี้จะทำให้การทดสอบหน่วยของคุณล้มเหลวหรือไม่ ดูเหมือนจะไม่ถูกต้อง การทดสอบหน่วยของคุณควรล้มเหลวด้วยเหตุผลเดียว: หากมีข้อบกพร่องในรหัสใน "หน่วย" นั้น

...do something with response...เพียงส่วนของรหัสที่มีความเกี่ยวข้องที่นี่คือ เยาะเย้ยส่วนที่เหลือ


2
โปรดจำไว้ว่าคุณจะต้องเก็บลายเซ็นวัตถุจำลองของคุณและคืนค่าให้ตรงกับสิ่งที่สร้างขึ้นโดย Hadoop webservice ตลอดการเปลี่ยนแปลงที่หลีกเลี่ยงไม่ได้สำหรับบริการดังกล่าว
pcurry

มันไม่ค่อยคุ้มค่าที่จะทดสอบส่วนประกอบนอกระบบเช่น Hadoop แต่ถ้าคุณเรียกใช้บริการทางเว็บที่กำหนดเองที่ทีมหรือองค์กรอื่นจัดทำคุณอาจต้องการทดสอบเพื่อป้องกันตัวเอง ด้วยวิธีนี้เมื่อสิ่งผิดปกติคุณสามารถตรวจสอบได้อย่างรวดเร็วว่าปัญหาคือรหัสของคุณหรือบริการเว็บ นี่ไม่ใช่การทดสอบหน่วยให้ทำงานโดยอัตโนมัติ เป็นการวินิจฉัยเพื่อให้ทำงานได้ตามต้องการ
kevin cline

@ kevincline ฉันเห็นด้วยอย่างยิ่งกับความจำเป็นของการทดสอบที่คุณเสนอและแน่นอนว่าฉันเขียนไว้ในงานประจำวันของฉันและได้พิสูจน์ตนเองว่ามีประโยชน์ แต่โดยนิยามแล้วการทดสอบหน่วยไม่ใช่ซึ่งเป็นคำถามที่เกี่ยวกับ :) พิจารณาสิ่งนี้: ถ้าเป็นการทดสอบหน่วยและรหัสล้มเหลวเนื่องจากเว็บเซอร์ถูกเปลี่ยนหน่วย "หน่วย" ที่คุณกำลังทดสอบคืออะไร? ความล้มเหลวอะไรกันแน่ คุณไม่ได้ทำการทดสอบแยกอย่างที่จำเป็นสำหรับการทดสอบหน่วย
Andres F.

1
@AndresF: ฉันคิดว่าเราอยู่ในข้อตกลงที่มีความรุนแรง: "[การวินิจฉัย] ไม่ใช่การทดสอบหน่วย ... "
kevin cline

@kevincline ถูกต้อง! ฉันอ่านความคิดเห็นของคุณผิด!
Andres F.

5

ฉันไม่เห็นด้วยกับ "อย่าจำลองวัตถุที่คุณไม่ได้เป็นเจ้าของ" เมื่อคุณทำการทดสอบหน่วย

จุดประสงค์ของการมีอยู่ของ mocks คือข้อเท็จจริงที่ว่าจะมีโมดูลห้องสมุดชั้นเรียนที่เราจะไม่เป็นเจ้าของ

ข้อเสนอแนะของฉันสำหรับสถานการณ์ของคุณคือการเยาะเย้ยโทรบริการเว็บ

ตั้งค่าการเยาะเย้ยในลักษณะที่จะส่งคืนข้อมูลกลับไปที่โมดูลของคุณ
ตรวจสอบให้แน่ใจว่าคุณครอบคลุมทุกสถานการณ์เช่นเมื่อข้อมูลที่ส่งคืนเป็นโมฆะเมื่อข้อมูลที่ส่งคืนนั้นถูกต้อง ฯลฯ

และสำหรับรหัสที่คุณเป็นเจ้าของความรับผิดชอบของคุณในฐานะนักพัฒนาคือการทำให้แน่ใจว่ารหัสที่คุณกำลังเขียนนั้นมีประสิทธิภาพตามที่คาดไว้ในทุกสถานการณ์


1

ฉันจะใช้บางอย่างเช่น EasyMock สำหรับการทดสอบนี้ กรอบการเยาะเย้ยเป็นวิธีที่เหมาะในการลบการอ้างอิงภายนอกในชั้นเรียนและให้คุณควบคุมผลการพึ่งพาภายนอกทั้งหมดในระหว่างการทดสอบ เพื่อขยายตัวอย่างของคุณเล็กน้อย:

class WebClass {

private WebServiceInterface webserviceInterface;

    void method(){
        R result = webServiceInterface.performWebServiceCall();
        ... do something with result
    }

    public void setWebServiceInterface(WebServiceInterface webServiceInterface){
        this.webServiceInterface = webServiceInterface;
    }
}


interface WebServiceInterface {

   R performWebServiceCall();

}


class WebClassTest {

private WebServiceInterface mock;    
private R sampleResult = new R();

    @Before
    public void before(){
        mock = EasyMock.createMock(WebServiceInterface.class);
    }


    @Test
    public void test() {
        WebClass classUnderTest = new WebClass();
        EasyMock.expect(mock.performWebServiceCall()).andReturn(sampleResult);
        classUnderTest.setWebServiceInterface(mock);
        classUnderTest.method();
        EasyMock.verify(mock);
    }
}

สิ่งแรกที่คุณต้องทำคือการแยกตรรกะในชั้นเรียนของคุณที่คุณใช้ Jersey เพื่อรับ WebResource และเรียกบริการเว็บลงในชั้นเรียนที่แยกต่างหาก การสร้างอินเทอร์เฟซสำหรับคลาสนี้จะช่วยให้คุณสร้างจำลองที่คุณสามารถกำหนดพฤติกรรมได้

เมื่อสร้างส่วนต่อประสานนี้แล้วคุณสามารถสร้างจำลองโดยใช้ EasyMock ซึ่งจะส่งคืนวัตถุที่ระบุไว้ในกรณีทดสอบของคุณ ตัวอย่างด้านบนคือการทำให้โครงสร้างการทดสอบจำลองเป็นเรื่องง่ายขึ้นและส่วนต่อประสานของคุณจะทำงานอย่างไร

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับกรอบการเยาะเย้ยโปรดดูคำถามนี้ นอกจากนี้ตัวอย่างนี้สมมติว่าการใช้ Java แต่กรอบการเยาะเย้ยมีให้บริการในทุกภาษาและแม้ว่าพวกเขาจะถูกนำไปใช้งานที่แตกต่างกันพวกเขาจะทำงานในลักษณะเดียวกัน


1

Mocks เป็นที่ยอมรับในกรณีนี้ แต่คุณไม่ต้องการ แทนการทดสอบหน่วยmethod()แทนที่จะทดสอบเฉพาะส่วนที่จัดการกับการตอบสนอง

แยกฟังก์ชั่นที่ใช้ResponseData(ชนิดใดก็ตามที่เหมาะสม) แล้วทำการดำเนินการ

แทนที่จะเยาะเย้ยตอนนี้คุณเพียงสร้างออบเจกต์ ResponseData และส่งต่อไป

คุณสามารถออกจากการเรียกใช้บริการเพื่อการทดสอบการรวมเข้าด้วยกัน - ซึ่งจะครอบคลุมmethod()ทั้งหมด


0

สิ่งที่ฉันทำและใช้งานได้:

  1. มี webservices การโทรโค้ดทั้งหมดผ่านพร็อกซี
  2. พร็อกซีเรียกคลาสที่คงที่รู้ว่าเราใช้พร็อกซีหรือไม่และเปลี่ยนเส้นทางตามนั้น Mocks เป็นเพียง HashMaps ที่แต่ละคำขอส่งกลับคำตอบที่กำหนด
  3. เรียกใช้การทดสอบหลายครั้งตามลำดับนี้:

3.1 ก่อนอื่นให้ทำการทดสอบเว็บเซอร์ จากแต่ละเครื่องแม้แต่เครื่องของนักพัฒนา นี่คือเว็บเซอร์วิสจริง แต่ทำงานในสภาพแวดล้อมการพัฒนา ซึ่งหมายความว่าเว็บเซอร์วิสไม่สามารถหยุดหรือตอบกลับค่าที่ผิดพลาดได้เพราะมิฉะนั้นนักพัฒนาซอฟต์แวร์ทุกคนบ่นว่าเขาไม่สามารถคอมไพล์ได้

3.2 จากนั้นทำการทดสอบหน่วยภายในของแอปพลิเคชันทั้งหมด ซึ่งหมายความว่า webservices ทั้งหมดถูกเยาะเย้ยและทดสอบการทดสอบที่ดำเนินต่อไปเช่นเดียวกับ 3.1 (และพวกเขาควรผ่านเช่นกันมิฉะนั้น mocks ผิด) และถูกเรียกใช้โดยแอปพลิเคชันจริงราวกับว่าพวกเขาถูกใช้งานจริง หาก mocks ผิดคุณสามารถรันการทดสอบใน 3.1 และบันทึกค่าเหล่านั้น (ร้องขอตอบกลับ) ใน HashMap

3.3 จากนั้นการทดสอบเดียวกันกับ 3.2 จะถูกเรียกใช้ แต่คราวนี้เทียบกับ webservices จริงที่ทำงานในสภาพแวดล้อมการพัฒนา

หลังจากสิ่งเหล่านี้เสร็จสมบูรณ์สำหรับสภาพแวดล้อมการผลิตจริงคุณเพียงแค่ต้องให้ที่อยู่ที่แท้จริงสำหรับแต่ละเว็บเซอร์ หวังว่านี่จะไม่ต้องการการเปลี่ยนแปลงในการกำหนดค่ามากเกินไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.