การทดสอบหน่วยสำหรับท่อส่งข้อมูลที่ประกอบด้วยฟังก์ชันหนึ่งบรรทัด


10

การอ่านบทนำเชิงปฏิบัติของแมรี่โรสคุกเกี่ยวกับการเขียนโปรแกรมเชิงฟังก์ชั่นเธอเป็นตัวอย่างของรูปแบบการต่อต้าน

def format_bands(bands):
    for band in bands:
        band['country'] = 'Canada'
        band['name'] = band['name'].replace('.', '')
        band['name'] = band['name'].title()

ตั้งแต่

  • ฟังก์ชั่นทำมากกว่าหนึ่งอย่าง
  • ชื่อไม่ได้อธิบาย
  • มันมีผลข้างเคียง

ในฐานะที่เป็นโซลูชั่นที่นำเสนอเธอแนะนำให้ใช้ฟังก์ชันที่ไม่ระบุชื่อไปป์ไลน์

pipeline_each(bands, [call(lambda x: 'Canada', 'country'),
                      call(lambda x: x.replace('.', ''), 'name'),
                      call(str.title, 'name')])

อย่างไรก็ตามเรื่องนี้ดูเหมือนว่าฉันจะมีข้อเสียของการเป็นที่ทดสอบได้น้อยลง; อย่างน้อย format_bands อาจมีการทดสอบหน่วยเพื่อตรวจสอบว่ามันเป็นสิ่งที่มันหมายถึง แต่วิธีการทดสอบท่อ? หรือความคิดที่ว่าฟังก์ชั่นนิรนามนั้นอธิบายตนเองได้โดยที่พวกเขาไม่จำเป็นต้องทำการทดสอบ?

แอปพลิเคชันที่ใช้งานจริงของฉันสำหรับสิ่งนี้กำลังพยายามทำให้pandasโค้ดของฉันทำงานได้มากกว่า ฉันมักจะมีขั้นตอนในการ "munging"

def munge_data(df)
     df['name'] = df['name'].str.lower()
     df = df.drop_duplicates()
     return df

หรือเขียนใหม่ในสไตล์ไปป์ไลน์:

def munge_data(df)
    munged = (df.assign(lambda x: x['name'].str.lower()
                .drop_duplicates())
    return munged

ข้อเสนอแนะสำหรับแนวทางปฏิบัติที่ดีที่สุดในสถานการณ์เช่นนี้?


4
ฟังก์ชั่นแลมบ์ดาแต่ละอันนั้นเล็กเกินไปสำหรับการทดสอบหน่วย ทดสอบผลลัพธ์สุดท้าย หากต้องการใช้อีกวิธีหนึ่งฟังก์ชั่นที่ไม่ระบุชื่อจะไม่สามารถทำการทดสอบได้ดังนั้นอย่าเขียนฟังก์ชั่นนี้เป็นฟังก์ชั่นที่ไม่ระบุชื่อ
Robert Harvey

คำตอบ:


1

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

มีฟังก์ชั่นที่มีอยู่แล้วเช่นiter(ในกรณีนี้ชื่อpipeline_foreach) ซึ่งดำเนินการกับองค์ประกอบทั้งหมดในรายการ ไม่จำเป็นต้องทำซ้ำกับforลูป นอกจากนี้การใช้การดำเนินการรายการที่รู้จักทำให้เจตนาของคุณชัดเจน ด้วยmapคุณกำลังเปลี่ยนค่า ในขณะที่iterคุณกำลังแสดงผลข้างเคียงกับแต่ละองค์ประกอบ ด้วยforลูปคุณ ... ดีคุณไม่รู้จริงๆจนกระทั่งมองผ่าน

ตัวอย่างโค้ดที่ถูกแก้ไขนั้นยังใช้งานไม่ได้เพราะมัน (เท่าที่ฉันสามารถบอกได้) เปลี่ยนแปลงค่าในรายการโดยไม่ส่งคืนเพื่อป้องกันการวางท่อหรือองค์ประกอบของฟังก์ชันเพิ่มเติม วิธีที่แนะนำหน้าที่mapจะสร้างรายการใหม่ของวงดนตรีที่มีการปรับปรุงและcountry nameจากนั้นคุณสามารถไพพ์ที่เอาต์พุตไปยังฟังก์ชันถัดไปหรือเขียนmapด้วยฟังก์ชันอื่นที่ใช้รายการแบนด์ ด้วยiterมันเหมือนปลายท่อส่ง

ฉันคิดว่ารหัสผลลัพธ์สุดท้ายมีฟังก์ชั่นเล็ก ๆ น้อย ๆ ที่รบกวนการทดสอบที่นี่ ท้ายที่สุดคุณไม่จำเป็นต้องเขียนหน่วยทดสอบreplaceหรือ titleตอนนี้บางทีคุณอาจต้องการรวมสิ่งเหล่านี้เข้าด้วยกันในฟังก์ชั่นของคุณและทดสอบหน่วยว่าชุดค่าผสมที่ต้องการสามารถทำได้ในรายการเดียว ตัวเองก็อาจจะมีการเปลี่ยนแปลงเพียงformat_bandsเพื่อเอกพจน์ลดลงสำหรับวงและเรียกformat_band pipeline_each(bands, format_band)จากนั้นคุณสามารถทดสอบ format_band เพื่อให้แน่ใจว่าคุณจะไม่ลืมอะไรบางอย่าง

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

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