Kiểm tra đơn vị cho các đường ống munging dữ liệu được tạo thành từ các hàm một dòng


10

Đọc Giới thiệu thực tế về lập trình chức năng của Mary Rose Cook , cô đưa ra như một ví dụ về chống mẫu

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

từ

  • chức năng làm nhiều hơn một điều
  • tên không được mô tả
  • nó có tác dụng phụ

Là một giải pháp được đề xuất, cô đề nghị các chức năng ẩn danh

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

Tuy nhiên, điều này đối với tôi dường như có nhược điểm là thậm chí ít kiểm chứng hơn; ít nhất format_band có thể có một bài kiểm tra đơn vị để kiểm tra xem nó có ý nghĩa gì không, nhưng làm thế nào để kiểm tra đường ống dẫn? Hay là ý tưởng rằng các hàm ẩn danh tự giải thích đến mức chúng không cần phải được kiểm tra?

Ứng dụng trong thế giới thực của tôi cho việc này là cố gắng làm cho pandasmã của tôi có nhiều chức năng hơn. Tôi thường sẽ có một số loại đường ống bên trong một chức năng "munging"

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

Hoặc viết lại theo kiểu đường ống:

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

Bất kỳ đề xuất cho thực hành tốt nhất trong loại tình huống này?


4
Các hàm lambda riêng lẻ này quá nhỏ để kiểm tra đơn vị. Kiểm tra kết quả cuối cùng. Nói cách khác, các hàm ẩn danh không thể kiểm tra được đơn vị, vì vậy đừng viết hàm dưới dạng hàm ẩn danh nếu bạn dự định kiểm tra đơn vị nó một cách riêng lẻ.
Robert Harvey

Câu trả lời:


1

Tôi nghĩ rằng bạn đã bỏ lỡ có lẽ phần quan trọng hơn của ví dụ đã sửa. Thay đổi cơ bản hơn về mã là từ phương thức hoạt động trên tất cả các giá trị trong danh sách sang hoạt động trên một phần tử.

Đã tồn tại các hàm như iter(trong trường hợp này có tên pipeline_foreach) thực hiện một thao tác nhất định trên tất cả các thành phần trong danh sách. Không cần phải lặp lại điều đó với một forvòng lặp. Cũng sử dụng một hoạt động danh sách nổi tiếng làm cho ý định của bạn rõ ràng. Với mapbạn đang chuyển đổi các giá trị. Với iterbạn đang thực hiện một hiệu ứng phụ với từng yếu tố. Với forvòng lặp bạn là ... tốt, bạn không thực sự biết cho đến khi bạn xem qua nó.

Ví dụ sửa mã vẫn không có nhiều chức năng, bởi vì nó (theo như tôi có thể nói) làm thay đổi các giá trị trong danh sách mà không trả lại chúng, ngăn chặn thêm đường ống hoặc thành phần chức năng. Phương thức được ưu tiên về mặt chức năng mapsẽ tạo ra một danh sách mới các băng tần được cập nhật countryname. Sau đó, bạn có thể chuyển đầu ra sang chức năng tiếp theo hoặc soạn mapvới một chức năng khác có danh sách băng tần. Với iter, nó giống như một ngõ cụt.

Tôi nghĩ rằng mã kết quả cuối cùng có các hàm nhỏ quá tầm thường để bận tâm kiểm tra ở đây. Rốt cuộc, bạn không cần phải viết bài kiểm tra đơn vị chống lại replacehoặc title. Bây giờ có lẽ bạn muốn kết hợp chúng lại với nhau thành chức năng và bài kiểm tra đơn vị của riêng bạn rằng sự kết hợp mong muốn đạt được trên một mục duy nhất. Chính tôi, có lẽ tôi đã thay đổi format_bandsthành format_bandsố ít, bỏ vòng lặp for và gọi pipeline_each(bands, format_band). Sau đó, bạn có thể kiểm tra format_band để đảm bảo rằng bạn đã không quên điều gì đó.

Dù sao, vào mã của bạn. Ví dụ thứ hai của bạn về mã có vẻ nhiều đường ống-y. Nhưng điều đó một mình không cung cấp những lợi ích của lập trình chức năng. Trong thực tế, lập trình chức năng có nghĩa là đảm bảo tính tương thích của các chức năng với các chức năng khác bằng cách xác định khả năng tương thích của chúng chỉ theo các yếu tố đầu vào và đầu ra của chúng. Nếu có các tác dụng phụ ẩn bên trong chức năng, thì mặc dù đầu vào / đầu ra của nó xếp hàng với chức năng khác, bạn không thể biết liệu chúng có tương thích cho đến khi chạy không. Tuy nhiên, nếu hai chức năng không có hiệu ứng phụ và khớp đầu ra với đầu vào thì bạn có thể tạo đường ống hoặc soạn thảo chúng mà không phải lo lắng về kết quả không mong muốn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.