2011-09-19 27 views
7

Tôi đang viết kiểm tra đơn vị và nhận ngoại lệ khi cố gắng tăng sự kiện từ mô hình lớp trừu tượng. Đây là đoạn mã mẫu:C# và Moq, tăng sự kiện được khai báo trong giao diện từ mô hình lớp trừu tượng

public abstract class AbstractBase : EntityObject 
    {} 

    [TestMethod] 
    public void MyTest() 
    { 

     var mock = new Mock<AbstractBase>(); 
     var notificationMock = entityMock.As<INotifyPropertyChanged>(); 

     var propertyChangedMapper = new PropertyChangedMapper(); 

     bool eventReceived = false; 
     propertyChangedMapper.MyPropertyChanged += 
      (sender, eventArgs) => 
       { 
        eventReceived = true; 
       }; 

     propertyChangedMapper.Subscribe((AbstractBase)notificationMock.Object); 

     Assert.IsFalse(eventReceived); 

     notificationMock.Raise(e=>e.PropertyChanged += null, 
            new PropertyChangedEventArgs("Property1")); 

     Assert.IsTrue(eventReceived); 
    } 

Rõ ràng là tôi có thể sử dụng mô hình trên INotifyPropertyChanged và sự kiện được tăng tốt, nhưng bên trong PropertyChangedMapper tôi cần phải đúc người gửi để AbstractBase mà thất bại nếu sử dụng Mock<INotifyPropertyChanged>

EDIT: Theo đề xuất sử dụng Mock.As<>() có vẻ là cách đúng đắn, vấn đề duy nhất ở trên là sự kiện tăng từ notificationMock không liên quan gì đến bản gốc của đối tượng. Mã số:

 notificationMock.Object.PropertyChanged += (s, e) => 
     { 
      var result = "this one is fired as it should"; 
     }; 

     mock.Object.PropertyChanged += (s, e) => 
     { 
      var result = "this one is not called but is actually what I need"; 
     }; 

     notificationMock.Raise(e => e.PropertyChanged += null, 
       new PropertyChangedEventArgs("Property1")); 
+0

Không cần biết người nào gọi, miễn là người nào gọi. Đoán của tôi là bạn có thể thực sự thiết lập một trong hai hoặc khác. Nhưng thiết lập cả hai sẽ dẫn đến giả trong nội bộ lựa chọn một trong khác. –

+0

Để có thêm bằng chứng cho thấy nó không quan trọng được gọi, hãy xem xét rằng hệ thống kiểu hoạt động tương tự cho các thành viên ảo và phần ghi đè của chúng. Ví dụ, nếu bạn thêm vào AbstractBase một ghi đè cho sự kiện INPC của EntityObject, không có cách nào cho bất kỳ mã nào dùng AbstractBase để buộc phiên bản của EntityObject được gọi. Ngay cả khi bạn truyền vào EntityObject, thành viên AbstractBase sẽ được gọi. Khi một thành viên cơ sở bị ghi đè, chỉ có lớp bắt nguồn mới có thể truy cập thành viên cơ sở ban đầu. –

Trả lời

1

Bạn có thể làm các diễn viên mong muốn nếu bạn thực hiện mô hình một mult-giả của bạn. Vì Moq mocks được gắn với một loại cá nhân thông qua đối số chung, bạn phải dần dần thêm các giao diện bổ sung hoặc siêu lớp vào mô hình, và sau đó sử dụng sản phẩm cuối cùng trong thử nghiệm của bạn. Một ví dụ nhanh về cách thực hiện điều này là dưới đây.

var baseMock = new Mock<AbstractBase>(); 
var inpcMock = baseMock.As<INotifyPropertyChanged>(); 

// ...setup event... 

propertyChangedMapper.Subscribe(inpcMock.Object); 

// ... assertions ... 
+1

Tính năng tuyệt vời! Tuy nhiên có vẻ như sự kiện KHÔNG được tăng lên thông qua 'inpcMock.Raise (e => e.PropertyChanged + = null, PropertyChangedEventArgs mới ("Property1")); '- bất kỳ ý tưởng nào tại sao? – Paul

+0

Vui lòng xem cập nhật ở trên – Paul

1

Cho cách bạn thực hiện việc này, không có triển khai sự kiện. Giao diện chính nó chỉ là hợp đồng mà nói "Tôi có một sự kiện PropertyChanged." Nếu bạn muốn nâng cao sự kiện đó, bạn phải cung cấp một trình xử lý, ngay cả khi nó không làm gì cả. Thực hiện sự kiện PropertyChanged trong lớp được mô phỏng của bạn để nâng cao sự kiện.

UPDATE:

Hãy thử mã này cho AbstractBase của bạn:

public abstract class AbstractBase : INotifyPropertyChanged 
{ 
    public virtual event PropertyChangedEventHandler PropertyChanged; 
    private void NotifyPropertyChanged(String info) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(info)); 
     } 
    } 
} 
+0

Vậy chính xác nên làm gì để giải quyết ngoại lệ này? – Paul

+1

Như mã như "abstractBase trừu tượng công cộng: INotifyPropertyChanged {}" không thể biên dịch, tôi nghĩ rằng anh ta vừa rút ngắn mã ở đây ... – David

+0

@Paul: Xem cập nhật. –

1

là sự kiện PropertyChanged bạn khai báo là một sự kiện virtual?

public abstract class AbstractBase : INotifyPropertyChanged 
{ 
    public virtual event PropertyChangedEventHandler PropertyChanged; 
} 

(Xem thêm:. Jon Skeet on virtual events)

+0

Vui lòng xem chỉnh sửa ở trên – Paul

+0

Tôi đoán tôi không rõ ràng về vấn đề này. Mã ban đầu của bạn làm việc tốt cho tôi (không có tất cả các công cụ 'As <>()'). – ladenedge

+0

Làm cho sự kiện ảo hoạt động quá, nhưng chỉ khi đây là lớp của tôi thực hiện các sự kiện. Khi kế thừa từ các lớp cơ sở đã có triển khai thực hiện - không có cách nào để thực hiện các sự kiện ảo. Cảm ơn câu trả lời của bạn. – Paul

Các vấn đề liên quan