2009-08-18 38 views
18

Tôi sửa đổi một phương thức lớp định dạng một số ngày tham số đầu vào sau đó được sử dụng làm tham số trong một lời gọi phương thức vào lớp cơ sở (nằm trong một assembly khác).Nhạo một cuộc gọi phương thức lớp cơ sở với Moq

Tôi muốn xác minh rằng ngày tôi chuyển sang phương pháp của tôi có định dạng chính xác khi chúng được chuyển đến phương thức lớp cơ sở vì vậy tôi muốn Moq gọi phương thức lớp cơ sở. Điều này có thể xảy ra với Moq không?

Trả lời

12

Nếu tôi hiểu câu hỏi của bạn một cách chính xác, bạn có một lớp Một quy định tại một số hội đồng khác, và sau đó một lớp B thực hiện nhiều hay ít như thế này:

public class B : A 
{ 
    public override MyMethod(object input) 
    { 
     // Do something 
     base.MyMethod(input); 
    } 
} 

Và bây giờ bạn muốn xác minh cơ sở đó. MyMethod được gọi là?

Tôi không thấy cách bạn có thể thực hiện việc này bằng thư viện mô phỏng động. Tất cả các thư viện mô phỏng động (với ngoại lệ của TypeMock) hoạt động bằng cách tự động phát ra các lớp bắt nguồn từ kiểu được đề cập.

Trong trường hợp của bạn, bạn không thể yêu cầu Moq xuất phát từ A, vì bạn muốn kiểm tra B.

Điều này có nghĩa là bạn phải yêu cầu Moq cấp cho bạn Mock<B>. Tuy nhiên, điều này có nghĩa là kiểu phát xạ xuất phát từ B, và trong khi nó có thể ghi đè MyMethod (vẫn còn ảo) và gọi cơ sở của nó (B.MyMethod), nó không có cách nào để đến lớp gốc và xác minh rằng B gọi base.MyMethod .

Hãy tưởng tượng rằng bạn phải viết một lớp học (C) có nguồn gốc từ B. Trong khi bạn có thể ghi đè MyMethod, không có cách nào bạn có thể xác minh rằng B gọi A:

public class C : B 
{ 
    public override MyMethod(object input) 
    { 
     // How to verify that base calls its base? 
     // base in this context means B, not A 
    } 
} 

Một lần nữa với ngoại lệ có thể xảy ra TypeMock, thư viện mô phỏng động không thể làm nhẹ nhàng mà bạn không thể làm theo cách thủ công. Tuy nhiên, tôi cho rằng việc gọi phương thức cơ sở mà bạn đang cố gắng xác minh có một số hiệu ứng phụ quan sát được, vì vậy nếu có thể, bạn có thể sử dụng thử nghiệm dựa trên trạng thái thay vì thử nghiệm dựa trên hành vi để xác minh kết quả gọi phương thức ?

Trong mọi trường hợp, thử nghiệm dựa trên trạng thái phải là phương pháp mặc định của bạn trong hầu hết các trường hợp.

1

Đồng ý với dấu, không thể sử dụng Moq.

Tùy thuộc vào trường hợp của bạn, bạn có thể xem xét swithcing from inheritance to composition. Sau đó, bạn sẽ có thể giả lập sự phụ thuộc và xác minh phương thức của bạn. Tất nhiên trong một số trường hợp nó chỉ có thể không có giá trị nó.

1

quấn phương pháp lớp cơ sở trong một phương pháp và thiết lập phương thức đó ví dụ:

public class B : A 
{ 
    public virtual BaseMyMethod(object input) 
    { 
     // Do something 
     base.MyMethod(input); 
    }  
public override MyMethod(object input) 
    { 
     // Do something 
     BaseMyMethod(input); 
    } 
} 

và bây giờ Thiết lập các BaseMyMethod

0

tôi tìm thấy giải pháp này - xấu xí nhưng nó có thể làm việc.

var real = new SubCoreClass();       
var mock = new Mock<SubCoreClass>(); 
mock.CallBase = true; 

var obj = mock.Object; 

mock 
    .Setup(c => c.Execute()) 
    .Callback(() => 
     {                  
     obj.CallBaseMember(typeof(Action), real, "Execute");    
     Console.WriteLine(obj.GetHashCode()); 
     } 
    ); 

public static Delegate CreateBaseCallDelegate(object injectedInstance, Type templateDelegate, object instanceOfBase, string methodName) 
{ 
    var deleg = Delegate.CreateDelegate(templateDelegate, instanceOfBase, methodName); 
    deleg.GetType().BaseType.BaseType.GetField("_target", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(deleg, injectedInstance); 

    return deleg; 
} 

public static object CallBaseMember(this object injectedInstance, Type templateDelegate, object instanceOfBase, string methodName, params object[] arguments) 
{ 
    return CreateBaseCallDelegate(injectedInstance, templateDelegate, instanceOfBase, methodName).DynamicInvoke(arguments); 
} 
3

Đây là lớp cơ bản có thể chế nhạo. Nhưng bạn sẽ phải sửa đổi lớp đích.

Đối với ex.DerivedClass kéo dài BaseClass. BaseClass có phương pháp MethodA(), MethodB(), MethodC() ... Các DerivedClass có phương pháp này:

void MyMethod() { 
    this.MethodA(); 
    this.MethodB(); 
    this.MethodC(); 
} 

Bạn muốn lớp cơ sở mô hình để xác nhận rằng tất cả MethodA(), MethodB(), MethodC() đang được gọi là bên MyMethod().

Bạn phải tạo một trường trong DerivedClass:

class DerivedClass { 
    private BaseClass self = this; 
    ... 
} 

Và cũng Bạn phải thay đổi MyMethod():

void MyMethod() { 
    self.MethodA(); 
    self.MethodB(); 
    self.MethodC(); 
} 

Ngoài ra thêm một phương pháp, mà có thể tiêm trường này.self với đối tượng Mock

public void setMock(BaseClass mock) { 
    this.self = mock; 
} 

Bây giờ bạn có thể thử:

DerivedClass target = new DerivedClass(); 
BaseClass mock = new Mock(typeof(BaseClass)); 
target.setMock(mock); 
target.MyMethod(); 

mock.verify(MethodA); 
mock.verify(MethodB); 
mock.verify(MethodC); 

Sử dụng kỹ thuật này, bạn cũng có thể giả cuộc gọi phương thức lồng nhau.

+0

lỗi trình biên dịch: từ khóa 'this' không có sẵn trong ngữ cảnh hiện tại. Trong trường lớp có nguồn gốc. –

7

Kể từ năm 2013 với Moq mới nhất bạn có thể. Đây là example

public class ViewModelBase 
{ 
    public virtual bool IsValid(DateTime date) 
    { 
     //some complex shared stuff here 
    } 
} 

public class MyViewModel : ViewModelBase 
{ 
    public void Save(DateTime date) 
    { 
     if (IsValid(date)) 
     { 
      //do something here 
     } 
    } 
} 

public void MyTest() 
{ 
    //arrange 
    var mockMyViewModel = new Mock<MyViewModel>(){CallBase = true}; 
    mockMyViewModel.Setup(x => x.IsValid(It.IsAny<DateTime>())).Returns(true); 

    //act 
    mockMyViewModel.Object.Save(); 

    //assert 
    //do your assertions here 
} 
Các vấn đề liên quan