2010-07-19 22 views
25

Tôi đang cố gắng thử một lớp từ Microsoft Sync Framework. Nó chỉ có một hàm tạo bên trong. Khi tôi thử như sau:Mocking một loại với một hàm tạo nội bộ bằng cách sử dụng Moq

var fullEnumerationContextMock = new Mock<FullEnumerationContext>(); 

tôi nhận được lỗi này:

System.NotSupportedException: Parent does not have a default constructor. The default constructor must be explicitly defined.

Đây là stack trace:

System.Reflection.Emit.TypeBuilder.DefineDefaultConstructorNoLock(MethodAttributes attributes) System.Reflection.Emit.TypeBuilder.DefineDefaultConstructor(MethodAttributes attributes) System.Reflection.Emit.TypeBuilder.CreateTypeNoLock() System.Reflection.Emit.TypeBuilder.CreateType() Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType() Castle.DynamicProxy.Generators.ClassProxyGenerator.GenerateCode(Type[] interfaces, ProxyGenerationOptions options) Castle.DynamicProxy.DefaultProxyBuilder.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) Castle.DynamicProxy.ProxyGenerator.CreateClassProxyType(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options) Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors) Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, IInterceptor[] interceptors) Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, IInterceptor[] interceptors) Moq.Mock 1.<InitializeInstance>b__0() Moq.PexProtector.Invoke(Action action) Moq.Mock 1.InitializeInstance()

Làm thế nào tôi có thể làm việc vòng này?

+3

Cảm ơn câu hỏi này! Nó chỉ là sự tồn tại đã giúp tôi. Tôi đã, trên mã của riêng tôi, có thể làm cho các nhà xây dựng công khai. Thật không may điều này không thể giúp tôi trường hợp của bạn, nhưng bạn vẫn giúp tôi ra +1 – Marcel

Trả lời

17

Bạn không thể giả lập một loại không có hàm tạo công khai vì Moq sẽ không thể khởi tạo đối tượng thuộc loại đó. Tùy thuộc vào những gì bạn đang cố gắng thử nghiệm, bạn có một vài tùy chọn:

  1. Nếu có đối tượng nhà máy hoặc một số cách khác để lấy trường hợp FullEnumerationContext có lẽ bạn có thể sử dụng (xin lỗi, tôi không quen với khung công tác đồng bộ hóa)
  2. Bạn có thể sử dụng phản chiếu riêng tư để khởi tạo FullEnumerationContext, nhưng sau đó bạn sẽ không thể thử phương pháp trên đó.
  3. Bạn có thể giới thiệu giao diện và/hoặc đối tượng trình bao bọc có thể giả định rằng mã đang được kiểm tra có thể gọi. Việc triển khai thời gian chạy sẽ ủy nhiệm cho FullEnumerationContext thực, trong khi việc thực hiện thời gian thử nghiệm của bạn sẽ thực hiện bất kỳ hành động nào bạn cần.
+3

Thực ra bạn CÓ THỂ khởi tạo mô hình cho một lớp với một hàm tạo bên trong. Bạn chỉ cần thuộc tính InternalsVisibleTo thích hợp được áp dụng cho assembly đích, như được giải thích trong "Tính năng nâng cao" trong https://code.google.com/p/moq/wiki/QuickStart – kzu

+11

@kzu Điều đó sẽ không hoạt động trên thư viện của bên thứ ba vì bạn không tự xây dựng thư viện. – DBueno

3

Tôi không thực sự là một chuyên gia về Moq, nhưng tôi nghĩ bạn cần xác định các đối số cho hàm tạo. Trong Rhino Mocks bạn sẽ chỉ định chúng như sau:

var fullEnumerationContextMock = new Mock<FullEnumerationContext>(arg1, arg2); 

Nó có lẽ tương tự như trong Moq.

+1

Bất cứ ai có thể xác nhận nếu điều này là có thể với Moq? Tôi đang sử dụng Moq 3.1 – tjrobinson

+0

No. Không. Lâu đài sử dụng hàm tạo mặc định để tạo từng lớp. Ít nhất đó là những gì tôi đọc ở đây [tại GitHub] (https://github.com/castleproject/Core/blob/c06adf27bf7a0dfe94529a2563aca94bdedd1cb0/src/Castle.Core/DynamicProxy/Generators/Emitters/AbstractTypeEmitter.cs#L323) – durilka

+3

Đây chỉ là đúng nếu bạn là Moqing một cái gì đó với một nhà xây dựng không mặc định công cộng. Đối với một nhà xây dựng nội bộ (mặc định hoặc bằng cách khác), bạn đã hết may mắn. – RJFalconer

1

Dựa trên câu trả lời từ marcind tôi đã tạo ra một giao diện (IFullEnumerationContext) mà tôi thử và sau đó tôi đã có hai quá tải của phương pháp tôi đang cố gắng để kiểm tra, một trong đó có các FullEnumerationContext và khác mà mất IFullEnumerationContext. Nó không cảm thấy tuyệt vời, nhưng nó hoạt động. Mọi đề xuất hay cải tiến tốt hơn sẽ được hoan nghênh.

public override void EnumerateItems(FullEnumerationContext context) 
{ 
    List<ItemFieldDictionary> listItemFieldDictionary = EnumerateItemsCommon(); 
    context.ReportItems(listItemFieldDictionary); 
} 

public void EnumerateItems(IFullEnumerationContext context) 
{ 
    List<ItemFieldDictionary> listItemFieldDictionary = EnumerateItemsCommon(); 
    context.ReportItems(listItemFieldDictionary); 
} 
+0

Tôi nghĩ rằng sẽ tốt hơn nếu quá tải có 'FullEnumerationContext' đã bao bọc trường hợp ngữ cảnh trong' FullEnumerationContextWrapper' và sau đó chuyển nó vào quá tải chấp nhận 'IFullEnumerationContext'. Bằng cách đó chỉ có một trong những phương pháp này sẽ chứa tất cả các mã quan trọng. Một trong những khác sẽ là một tuyên bố một dòng mà không cần phải có một bài kiểm tra đơn vị liên kết với nó. – marcind

0

Thực ra bạn có thể. Mở tệp AssemblyInfo.cs của bạn và thêm dòng sau vào cuối,

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

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