Pengujian unit untuk pipa munging data yang terdiri dari fungsi satu garis

10

Membaca Pengantar Praktis untuk Pemrograman Fungsional Mary Rose Cook , ia memberikan contoh anti-pola

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

sejak

  • fungsi melakukan lebih dari satu hal
  • namanya tidak deskriptif
  • ini memiliki efek samping

Sebagai solusi yang diusulkan, ia menyarankan fungsi anonim pipelining

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

Namun bagi saya ini tampaknya memiliki kelemahan yang bahkan lebih tidak dapat diuji; setidaknya format_bands dapat memiliki unit test untuk memeriksa apakah ia melakukan apa yang dimaksudkan, tetapi bagaimana cara menguji pipa? Atau apakah gagasan bahwa fungsi anonim begitu jelas sehingga tidak perlu diuji?

Aplikasi dunia nyata saya untuk ini adalah mencoba membuat pandaskode saya lebih fungsional. Saya akan sering memiliki semacam pipa di dalam fungsi "munging"

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

Atau menulis ulang dengan gaya pipeline:

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

Adakah saran untuk praktik terbaik dalam situasi seperti ini?

Max Flander
sumber
4
Fungsi-fungsi lambda individu terlalu kecil untuk unit test. Uji hasil akhir. Dengan kata lain, fungsi anonim tidak dapat diuji unit, jadi jangan menulis fungsi sebagai fungsi anonim jika Anda berencana untuk mengujinya secara individual.
Robert Harvey

Jawaban:

1

Saya pikir Anda melewatkan mungkin bagian yang lebih penting dari contoh buku yang diperbaiki. Perubahan yang lebih mendasar pada kode adalah dari metode yang beroperasi pada semua nilai dalam daftar menjadi operasi pada satu elemen.

Sudah ada fungsi seperti iter(dalam hal ini bernama pipeline_foreach) yang melakukan operasi yang diberikan pada semua elemen dalam daftar. Tidak perlu menduplikasi dengan forloop. Juga menggunakan operasi daftar terkenal membuat niat Anda jelas. Dengan mapAnda mentransformasikan nilai. Dengan iterAnda melakukan efek samping dengan setiap elemen. Dengan forloop kamu ... yah, kamu tidak benar-benar tahu sampai kamu melihatnya.

Contoh kode yang dikoreksi masih sangat tidak fungsional, karena (sejauh yang saya tahu) mengubah nilai dalam daftar tanpa mengembalikannya, mencegah perpipaan atau komposisi fungsi lebih lanjut. Metode yang disukai secara fungsional mapakan membuat daftar band baru dengan pembaruan countrydan name. Kemudian Anda bisa menyalurkan output itu ke fungsi berikutnya atau menulis mapdengan fungsi lain yang mengambil daftar band. Dengan iter, itu seperti jalan buntu pipa.

Saya pikir kode hasil akhir memiliki fungsi kecil yang terlalu sepele untuk mengganggu pengujian di sini. Lagi pula, Anda tidak perlu menulis unit test melawan replaceatau title. Sekarang mungkin Anda ingin menyusun ini menjadi fungsi dan unit tes Anda sendiri bahwa kombinasi yang diinginkan tercapai pada satu item. Saya sendiri, saya mungkin akan berubah format_bandsmenjadi format_bandtunggal, menjatuhkan for loop, dan menelepon pipeline_each(bands, format_band). Kemudian Anda dapat menguji format_band untuk memastikan Anda tidak melupakan sesuatu.

Bagaimanapun, ke kode Anda. Contoh kode kedua Anda tampaknya lebih banyak pipeline-y. Tetapi itu saja tidak memberikan manfaat pemrograman fungsional. Dalam praktiknya, pemrograman fungsional berarti memastikan kompatibilitas fungsi dengan fungsi lain dengan mendefinisikan kompatibilitasnya hanya dalam hal input dan outputnya. Jika ada efek samping tersembunyi di dalam fungsi, maka terlepas dari input / output yang sejalan dengan fungsi lainnya, Anda tidak dapat mengetahui apakah mereka kompatibel hingga waktu berjalan. Namun, jika dua fungsi bebas efek samping dan cocok dengan input-ke-input maka Anda dapat menyalurkan atau menyusunnya dengan sedikit khawatir akan hasil yang tidak terduga.

Kasey Speakman
sumber