Xin lỗi vì sự hoại tử trên bài đăng này, nhưng tôi cảm thấy buộc phải cân nhắc một vài điều mà dường như không được chạm vào.
Trước hết - khi chúng tôi thấy mình cần truy cập vào các thành viên tư nhân trong một lớp trong quá trình kiểm tra đơn vị, thì đó thường là một lá cờ đỏ to, mập mà chúng tôi đã sử dụng trong cách tiếp cận chiến lược hoặc chiến thuật của mình và đã vô tình vi phạm nguyên tắc trách nhiệm duy nhất bằng cách đẩy hành vi nơi nó không thuộc về. Cảm thấy sự cần thiết phải truy cập các phương thức thực sự không có gì khác hơn một chương trình con bị cô lập của một quy trình xây dựng là một trong những sự cố phổ biến nhất của điều này; tuy nhiên, nó giống như sếp của bạn mong đợi bạn sẵn sàng cho công việc sẵn sàng và cũng có một số nhu cầu cần thiết để biết thói quen buổi sáng bạn đã trải qua để đưa bạn vào trạng thái đó ...
Trường hợp phổ biến nhất khác của điều này xảy ra là khi bạn thấy mình đang cố gắng kiểm tra "lớp thần" tục ngữ. Bản thân nó là một loại vấn đề đặc biệt, nhưng mắc phải cùng một vấn đề cơ bản với việc cần phải biết chi tiết thân mật của một thủ tục - nhưng đó là lạc đề.
Trong ví dụ cụ thể này, chúng tôi đã giao trách nhiệm khởi tạo đầy đủ đối tượng Bar cho hàm tạo của lớp FooBar. Trong lập trình hướng đối tượng, một trong những khách thuê cốt lõi là nhà xây dựng là "thiêng liêng" và cần được bảo vệ chống lại dữ liệu không hợp lệ sẽ làm mất hiệu lực trạng thái bên trong của chính nó và khiến nó bị thất bại ở một nơi khác ở phía dưới (trong đó có thể rất sâu đường ống dẫn.)
Chúng tôi đã không làm được điều đó ở đây bằng cách cho phép đối tượng FooBar chấp nhận một Bar chưa sẵn sàng tại thời điểm FooBar được xây dựng và đã bù đắp bằng cách "hack" đối tượng FooBar để đưa vấn đề vào chính nó tay.
Đây là kết quả của việc không tuân thủ một phần mười chương trình hướng đối tượng khác (trong trường hợp của Bar), đó là trạng thái của một đối tượng nên được khởi tạo hoàn toàn và sẵn sàng xử lý bất kỳ cuộc gọi đến nào cho các thành viên công khai của nó ngay sau khi tạo. Bây giờ, điều này không có nghĩa là ngay lập tức sau khi hàm tạo được gọi trong tất cả các trường hợp. Khi bạn có một đối tượng có nhiều kịch bản xây dựng phức tạp, thì tốt hơn là để lộ setters cho các thành viên tùy chọn của nó cho một đối tượng được triển khai theo mô hình thiết kế sáng tạo (Factory, Builder, v.v.) trong bất kỳ các trường hợp sau,
Trong ví dụ của bạn, thuộc tính "trạng thái" của Bar dường như không ở trạng thái hợp lệ trong đó FooBar có thể chấp nhận nó - vì vậy FooBar làm gì đó để khắc phục vấn đề đó.
Vấn đề thứ hai tôi đang thấy là có vẻ như bạn đang cố kiểm tra mã của mình chứ không phải thực hành phát triển dựa trên thử nghiệm. Đây chắc chắn là ý kiến của riêng tôi tại thời điểm này; nhưng, loại thử nghiệm này thực sự là một mô hình chống. Điều cuối cùng bạn làm là rơi vào cái bẫy nhận ra rằng bạn có các vấn đề thiết kế cốt lõi khiến mã của bạn không thể kiểm tra được sau khi thực tế, thay vì viết các bài kiểm tra bạn cần và sau đó lập trình cho các bài kiểm tra. Dù bạn gặp phải vấn đề gì, bạn vẫn nên kết thúc với cùng số lượng thử nghiệm và dòng mã nếu bạn thực sự đạt được triển khai RẮN. Vì vậy - tại sao thử và đảo ngược kỹ thuật của bạn thành mã có thể kiểm tra khi bạn chỉ có thể giải quyết vấn đề khi bắt đầu nỗ lực phát triển của mình?
Nếu bạn đã làm điều đó, thì bạn sẽ nhận ra sớm hơn rằng bạn sẽ phải viết một số mã khá rắc rối để kiểm tra thiết kế của bạn và sẽ có cơ hội sớm để điều chỉnh lại cách tiếp cận của bạn bằng cách chuyển hành vi sang triển khai dễ dàng kiểm tra.