Làm thế nào để giả định phương pháp với đối tượng mã hóa cứng?


11

Tôi đang làm việc trên một ứng dụng có nhiều lớp. Lớp truy cập dữ liệu để truy xuất và lưu dữ liệu từ nguồn dữ liệu, logic nghiệp vụ để thao tác dữ liệu, giao diện người dùng để hiển thị dữ liệu trên màn hình.

Tôi cũng làm thử nghiệm đơn vị của lớp logic kinh doanh. Yêu cầu duy nhất là kiểm tra luồng logic của lớp nghiệp vụ. Vì vậy, tôi sử dụng khung Moq để mô phỏng lớp truy cập dữ liệu và đơn vị kiểm tra lớp logic nghiệp vụ với MS Unit.

Tôi đang sử dụng lập trình giao diện để làm cho thiết kế tách rời càng nhiều càng tốt để thử nghiệm đơn vị có thể được thực hiện. Lớp doanh nghiệp gọi lớp truy cập dữ liệu thông qua giao diện.

Tôi đang đối mặt với một vấn đề khi tôi đang cố gắng thử nghiệm một trong những phương pháp logic kinh doanh. Phương thức đó thực hiện một số công việc và tạo một đối tượng và chuyển nó đến lớp truy cập dữ liệu. Khi tôi đang cố gắng giả định phương thức lớp truy cập dữ liệu đó thì nó không thể giả định thành công.

Ở đây tôi đang cố gắng tạo một mã demo để hiển thị vấn đề của mình.

Mô hình:

public class Employee
{
    public string Name { get; set; }
}

Lớp truy cập dữ liệu:

public interface IDal
{
    string GetMessage(Employee emp);
}

public class Dal : IDal
{
    public string GetMessage(Employee emp)
    {
        // Doing some data source access work...

        return string.Format("Hello {0}", emp.Name);
    }
}

Lớp logic nghiệp vụ:

public interface IBll
{
    string GetMessage();
}

public class Bll : IBll
{
    private readonly IDal _dal;

    public Bll(IDal dal)
    {
        _dal = dal;
    }

    public string GetMessage()
    {
        // Object creating inside business logic method.
        Employee emp = new Employee(); 

        string msg = _dal.GetMessage(emp);
        return msg;
    }
}

Bài kiểm tra đơn vị:

[TestMethod]
    public void Is_GetMessage_Return_Proper_Result()
    {
        // Arrange.
        Employee emp = new Employee; // New object.

        Mock<IDal> mockDal = new Mock<IDal>();
        mockDal.Setup(d => d.GetMessage(emp)).Returns("Hello " + emp.Name);

        IBll bll = new Bll(mockDal.Object);

        // Act.

        // This will create another employee object inside the 
        // business logic method, which is different from the 
        // object which I have sent at the time of mocking.
        string msg = bll.GetMessage(); 

        // Assert.
        Assert.AreEqual("Hello arnab", msg);
    }

Trong trường hợp thử nghiệm đơn vị tại thời điểm chế nhạo tôi đang gửi một đối tượng Nhân viên nhưng khi gọi phương thức logic nghiệp vụ, nó đang tạo ra đối tượng Nhân viên khác bên trong phương thức. Đó là lý do tại sao tôi không thể chế nhạo đối tượng.

Trong trường hợp đó làm thế nào để thiết kế để tôi có thể giải quyết vấn đề?


Thông thường mẹo là bọc đối tượng trong một giao diện và làm cho tất cả người tiêu dùng sử dụng giao diện đó, sau đó bạn chỉ cần chế giễu giao diện, thay vào đó bạn có thể làm cho phương thức trở nên ảo và sau đó moq có thể giả định phương thức mà không cần giao diện. Tuy nhiên, không chắc chắn về tê giác hoặc những người khác trong trường hợp này.
Jimmy Hoffa

Câu trả lời:


12

Thay vì tạo một Employeeđối tượng trực tiếp bằng cách sử dụng new, lớp của bạn Bllcó thể sử dụng một EmployeeFactorylớp cho việc này, với một phương thức createInstance, được đưa vào thông qua hàm tạo:

 class EmployeeFactory : IEmployeeFactory
 {
       public Employee createInstance(){return new Employee();}
 }

Nhà xây dựng nên đưa đối tượng nhà máy thông qua một giao diện IEmployeeFactory, do đó bạn có thể thay thế nhà máy "thực" một cách dễ dàng bằng một nhà máy giả.

public class Bll : IBll
{
    private readonly IDal _dal;
    private readonly IEmployeeFactory _employeeFactory;

    public Bll(IDal dal, IEmployeeFactory employeeFactory)
    {
        _dal = dal;
        _employeeFactory=employeeFactory;
    }

    public string GetMessage()
    {
        // Object creating inside business logic method
        // *** using a factory ***
        Employee emp = _employeeFactory.createObject(); 
        // ...
    }
    //...
}

Nhà máy giả có thể cung cấp thử nghiệm với bất kỳ loại Employeeđối tượng nào bạn cần cho thử nghiệm của mình (ví dụ: createInstanceluôn có thể trả về cùng một đối tượng):

 class MockEmployeeFactory : IEmployeeFactory
 {
       private Employee _emp;

       public MockEmployeeFactory()
       {
          _emp = new Employee();
          // add any kind of special initializing here for testing purposes
       }

       public Employee createInstance()
       {
          // just for testing, return always the same object
          return _emp;
       }
 }

Bây giờ sử dụng giả này trong thử nghiệm của bạn nên thực hiện các mẹo.


Bạn có thể cho tôi một ví dụ mã, để tôi có thể hình dung lý thuyết của bạn?
Nhà phát

@DeveloperArnab: xem chỉnh sửa của tôi.
Doc Brown

Rất hữu ích ...
DeveloperArnab

4

Tôi sẽ coi nó là đơn vị duy nhất để kiểm tra.

Miễn là bạn kiểm soát tất cả các yếu tố đầu vào mà Employeeđối tượng được tạo ra, thực tế là nó được tạo ra trong đối tượng được thử nghiệm không nên quan trọng. Bạn chỉ cần một phương thức giả để trả về kết quả mong đợi nếu nội dung của đối số khớp với kỳ vọng.

Rõ ràng nó có nghĩa là bạn cần cung cấp logic tùy chỉnh cho phương thức giả. Logic nâng cao thường không thể được kiểm tra chỉ với loại giả "cho x return y".

Trên thực tế, bạn không nên làm cho nó trả về các đối tượng khác nhau trong các thử nghiệm so với trong sản xuất, bởi vì nếu bạn đã làm, bạn sẽ không kiểm tra mã sẽ tạo ra nó. Nhưng mã đó là một phần không thể thiếu của mã sản xuất và do đó cũng nên được bao phủ trong trường hợp thử nghiệm.


Có, tôi không bận tâm về các đầu vào của lớp truy cập dữ liệu, tôi chỉ muốn giả định đối tượng đó và trả về dữ liệu được mã hóa cứng để tôi có thể kiểm tra logic nghiệp vụ. Nhưng vấn đề là do hai đối tượng Nhân viên khác nhau, tôi không thể chế giễu phương thức lớp truy cập dữ liệu.
DeveloperArnab

@DeveloperArnab: Các đối tượng sẽ khác nhau, nhưng chúng sẽ có nội dung được biết đến. Vì vậy, tất cả những gì bạn cần làm là làm cho giả làm so sánh tùy chỉnh thay vì nhận dạng đối tượng.
Jan Hudec

@DeveloperArnab: Nếu bạn tiêm các Employeeđối tượng khác nhau trong các thử nghiệm, bạn sẽ không kiểm tra mã thường tạo ra nó. Vì vậy, bạn không nên thay đổi nó.
Jan Hudec

0

Đó là một số công cụ kiểm tra không thành công, bạn phải luôn sử dụng các giao diện và mọi thứ phải được tạo theo cách cho phép bạn trao đổi đối tượng dựa trên giao diện cho một giao diện khác.

Tuy nhiên, có những công cụ tốt hơn - lấy Microsoft Fakes (được gọi là Moles) cho phép bạn trao đổi bất kỳ đối tượng nào, ngay cả những đối tượng tĩnh và toàn cầu. Cần một cách tiếp cận cấp thấp hơn để thay thế các đối tượng để bạn không phải sử dụng giao diện ở mọi nơi trong khi vẫn giữ cách viết bài kiểm tra mà bạn đã quen.

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.