2011-11-08 6 views
7

Tôi đã đọc hầu hết các câu hỏi liên quan đến SO (here, herethere). Câu hỏi cuối cùng đề xuất bốn lựa chọn thay thế để tạo mã gọi các phương thức tĩnh có thể kiểm thử được. Tôi muốn hỏi về trường hợp cụ thể của tôi: Chúng tôi có một "lớp logic kinh doanh" hoặc "quy tắc" dự án trong đó có 45 lớp tĩnh (không có nhà nước, chỉ là phương pháp tĩnh). Hơn nữa, chúng không dễ dàng kiểm thử được: hầu hết chúng đều truy cập vào cơ sở dữ liệu và hệ thống tệp. Nó không phải là xấu, anyway: để truy cập vào cơ sở dữ liệu, họ sử dụng dụ duy nhất của một số lớp Mapper (tất cả các Mappers là Singletons). Bất cứ khi nào tôi cố gắng kiểm tra đơn vị, tôi chạy vào bức tường này. Vấn đề lớn nhất là đây là mã rất, rất quan trọng và những thay đổi đối với nó nên được lên kế hoạch rất cẩn thận. Câu hỏi của tôi: Tôi nên làm thế nào để làm cho đơn vị này dễ kiểm thử hơn? Tôi có nên viết 45 giao diện và sử dụng tiêm phụ thuộc không? Mặc dù vậy, làm thế nào để tôi lập/mock Mappers?Mã thử nghiệm đơn vị gọi các phương thức tĩnh

PS: Tôi đã đọc Michael Feathers' 'Làm việc với Legacy Code', vì vậy tài liệu tham khảo trực tiếp được hoan nghênh (sách khác quá :)

Sửa: Kể từ khi một số người cho biết các giải pháp có thể là nền tảng phụ thuộc Tôi đang làm việc trên .NET (C# và một số VB.NET)

Trả lời

10

Tình huống hiện tại có thể là không ai dám thay đổi bất kỳ thứ gì trong mã vì nó có thể bị hỏng theo cách bất ngờ. Hãy chắc chắn rằng tất cả mọi người hiểu rằng bạn đang cải thiện tình hình: Những thay đổi của bạn thể phá vỡ các mã nhưng không giống như trước, những vỡ sẽ tìm thấylần họ đã được tìm thấy, họ sẽ được cố định mãi mãi.

Điều đó nói rằng, bước tiếp theo phụ thuộc vào trải nghiệm của bạn và tín dụng của bạn với nhóm. Nếu bạn muốn chơi an toàn, sử dụng mã như thế này (cú pháp Java):

Mapper { 
    public static Mapper INSTANCE = new Mapper(); // NEW code 

    protected void doImpl() { // NEW CODE 
     ... code copied from impl()... // OLD code, NEW PLACE 
    } 

    public static void impl() { // OLD code 
     INSTANCE.doImpl(); // NEW code 
    } 

    // OLD code ... 
} 

Đây là một sự thay đổi rất đơn giản cho phép bạn ghi đè lên INSTANCE từ các bài kiểm tra của bạn. Đối với mã sản xuất, bạn không làm bất cứ điều gì và mặc định sẽ làm cho mã hoạt động chính xác như trước đây.

Bằng cách đó, bạn có thể thay thế một phương pháp tại một thời điểm. Bạn có thể dừng theo con đường này bất cứ lúc nào - mỗi thay đổi chỉ mất một vài phút và đó là tái cấu trúc: Mã này thực hiện chính xác những gì nó đã làm trước đó. Vì mỗi thay đổi quá nhỏ và không thể phá vỡ bất cứ điều gì, bạn có thể thay thế một phương pháp, viết tất cả các bài kiểm tra đơn vị mà bạn không thể viết trước, rửa sạch, lặp lại. Cuối cùng, nếu bạn không muốn/cần phải làm lại tất cả các phương pháp tĩnh, cách tiếp cận này cung cấp cho bạn tất cả các leeway bạn có thể yêu cầu.

Trong bước thứ hai, bạn có thể giới thiệu DI hoặc bất kỳ công nghệ nào khác sẽ làm bạn hài lòng. Ưu điểm của phương pháp này: Khi bạn đến với những thay đổi phức tạp, bạn sẽ có các bài kiểm tra đơn vị sẽ bảo vệ bạn.

Nếu bạn bắt đầu với DI, bạn phải thay đổi rất nhiều mã ở tất cả các loại địa điểm - mà không cần kiểm tra đơn vị thích hợp có thể bảo vệ bạn.

2

Câu hỏi của bạn thực sự liên quan đến nền tảng, trong thế giới Microsoft, bạn có thể sử dụng Microsoft Moles để kiểm tra các phương pháp tĩnh. Và giả lập phương pháp tĩnh.

Trong thế giới java có thể có các công cụ khác hoặc bạn nên tránh sử dụng các số liệu thống kê.

Trên nền tảng khác có các công cụ khác vv

Nói chung, bất kỳ phương pháp tĩnh sẽ làm cho mã của bạn ít kiểm chứng. Trong lựa chọn của tôi, tốt hơn là tránh các số liệu thống kê và người độc thân (tiểu bang toàn cầu) bằng mọi giá. Mã có thể kiểm tra là phần quan trọng nhất trong mã của bạn nếu bạn thay đổi bất kỳ điều gì sau này. Mã có thể kiểm tra thường là dễ đọc hơn.

Moles and Pex

3

Tận dụng giao diện của lớp Mapper và thay thế các chức năng ánh xạ với một thực hiện moc mới. Tôi nghĩ rằng bạn sẽ cần phải thực hiện các nhà máy trừu tượng mà sẽ tạo ra các trường hợp của Mappers. Vì vậy, làm cho một IMapperFactory và hai hiện thực của DBMapperFactory này và MocMapperFactory chuyển thể hiện của đối tượng này đến mã của bạn, nơi bạn truy cập vào các Mappers và tạo ra chúng bằng cách sử dụng cá thể này.

Gl.

+1

Âm thanh ok. Điều đó sẽ đảm bảo làm cho các phương thức tĩnh có thể kiểm tra được, nhưng làm thế nào về mã gọi chúng? Trên một lưu ý khác, chỉ tò mò ... Là "GI" một số loại chữ ký, hoặc là nó một từ viết tắt? (Tôi đến từ Argentina) –

+0

Gl == Good Luck :). Đối với mã sử dụng Mapper, bạn phải điều chỉnh nó để sử dụng giao diện nhà máy thay vì getInstance bởi singleton. – AlexTheo

1

Lớp tĩnh có thể được chế nhạo, mặc dù không biết bạn đang sử dụng ngôn ngữ/môi trường nào, nhưng không có cách nào để nói như thế nào.

Tôi đã có một codebase kết thúc chính xác như những gì bạn đã nói; chúng tôi đã tạo ra các giao diện và triển khai mặc định của một vài tá lớp tĩnh (đừng hoảng sợ - tạo mã). Mặc định này chỉ được giao cho những người độc thân.

Các lớp gọi đã được chuyển sang DI bằng cách sử dụng implon mặc định, nhưng sau đó dễ kiểm tra hơn. Các lớp tĩnh với các phụ thuộc vào các lớp tĩnh khác hoặc các trình đơn được chuyển sang sử dụng các impls mặc định.

Bạn thử một singleton giống như bất kỳ lớp nào khác - nếu nó có số getInstance (hoặc tương đương), bạn có thể làm cho nó trở lại bất cứ điều gì bạn muốn. Hoặc bạn có thể đi cùng một tuyến đường và sử dụng DI.

+0

OK, tôi đang sử dụng .NET (câu hỏi được cập nhật). Có thể giả lập một lớp tĩnh dễ dàng không? –

+0

@dario_ramos Tôi không có ý kiến, nhưng câu trả lời của đồng nghiệp ngụ ý bạn có thể. –

1

Câu hỏi hay! Bạn có thể giả lập lớp Mapper của bạn bằng cách tạo một lớp mới kế thừa từ lớp singleton Mapper sau đó và sử dụng nó để chặn tất cả các cuộc gọi đến cơ sở dữ liệu của bạn.