2009-11-02 48 views
1

我是Rhino Mocks的新手,所以我可能會錯過一些完整的東西。如何重置存根中屬性的結果而不重置整個存根?

可以說我有一個接口用了半打屬性:

public interface IFoo { 
    string Foo1 { get; } // Required non-null or empty 
    string Foo2 { get; } // Required non-null or empty 
    string Foo3 { get; } 
    string Foo4 { get; } 
    int Foo5 { get; } 
    int Foo6 { get; } 
} 

並採用了類似的對象,但沒有相同的限制,並創建一個IFoo的情況下實現:

public interface IFooLikeObject { 
    string FooLikeObject1 { get; } // Okay non-null or empty 
    string FooLikeObject2 { get; } // Okay non-null or empty 
    string FooLikeObject3 { get; } 
    string FooLikeObject4 { get; } 
    string FooLikeObject5 { get; } // String here instead of int 
    string FooLikeObject6 { get; } // String here instead of int 
} 

public class Foo : IFoo { 
    public Foo(IFooLikeObject fooLikeObject) { 

    if (string.IsNullOrEmpty(fooLikeObject.Foo1)) { 
     throw new ArgumentException("fooLikeObject.Foo1 is a required element and must not be null.") 
    } 

    if (string.IsNullOrEmpty(Foo2)) { 
     throw new ArgumentException("fooLikeObject.Foo2 is a required element and must not be null") 
    } 

    // Make all the assignments, including conversions from string to int... 

    } 
} 

現在在我的測試中,我想測試在適當的時候拋出異常以及在從字符串到int的轉換失敗期間拋出的異常。

因此,我需要將IFooLikeObject存儲爲我爲當前未測試的值返回有效值,因爲我不想在每種測試方法中複製此代碼,所以我將其解壓縮爲單獨的方法。

public IFooLikeObject CreateBasicIFooLikeObjectStub(MockRepository mocks) { 
    IFooLikeObject stub = mocks.Stub<IFooLikeObject>(); 

    // These values are required to be non-null 
    SetupResult.For(stub.FooLikeObject1).Return("AValidString"); 
    SetupResult.For(stub.FooLikeObject2).Return("AValidString2"); 
    SetupResult.For(stub.FooLikeObject5).Return("1"); 
    SetupResult.For(stub.FooLikeObject6).Return("1"); 
} 

測試Foo1,2,5時,此作品不夠好測試Foo3和Foo4,但或6我得到:

System.InvalidOperationException : The result for IFooLikeObject.get_FooLikeObject1(); has already been setup. Properties are already stubbed with PropertyBehavior by default, no action is required 

例如:

[Test] 
void Constructor_FooLikeObject1IsNull_Exception() { 
    MocksRepository mocks = new MocksRepository(); 
    IFooLikeObject fooLikeObjectStub = CreateBasicIFooLikeObjectStub(mocks); 

// This line causes the exception since FooLikeObject1 has already been set in CreateBasicIFooLikeObjectStub() 
    SetupResult.For(fooLikeObjectStub.FooLikeObject1).Return(null); 

    mocks.ReplayAll(); 

    Assert.Throws<ArgumentException>(delegate { new Foo(fooLikeObjectStub); }); 
} 

如何我設置了它,以便我可以覆蓋已經設置了返回值的單個屬性,而無需重做所有其他值。

回答

1

這可以通過使用Repeat.Any()結構來完成。

使用SetupResult.For語法我沒有測試過這一點,但它與lambda語法的工作原理:

public IFooLikeObject CreateBasicIFooLikeObjectStub(MockRepository) { 
    IFooLikeObject stub = MockRepository.GenerateStub<IFooLikeObject>(); 

    // These values are required to be non-null 
    stub.Stub(s => s.FooLikeObject1).Return("AValidString"); 
    stub.Stub(s => s.FooLikeObject2).Return("AValidString2"); 
    stub.Stub(s => s.FooLikeObject5).Return("1"); 
    stub.Stub(s => s.FooLikeObject6).Return("1"); 
} 

[Test] 
void Constructor_FooLikeObject1IsNull_Exception() { 
    IFooLikeObject fooLikeObjectStub = CreateBasicIFooLikeObjectStub(); 

    // This line no longer causes an exception 
    stub.Stub(s => s.FooLikeObject1).Return(null).Repeat.Any(); // The Repeat.Any() is key. Otherwise the value wont be overridden. 

    Assert.Throws<ArgumentException>(delegate { new Foo(fooLikeObjectStub); }); 
} 

我發現唯一需要注意的是你不能做兩次。

0

我可能會錯過一些東西,但是您是否嘗試過這樣做?

var stub = mocks.Stub<IFooLikeObject>(); 

stub.FooLikeObject1 = "AValidString"; 
stub.FooLikeObject2 = "AValidString2"; 
stub.FooLikeObject5 = "1"; 
stub.FooLikeObject6 = "1"; 

使用存根,您可以將屬性設置爲您希望它們直接設置的值。

如果是隻讀屬性,你可以做這樣的:

var stub = mocks.Stub<IFooLikeObject>(); 

stub.Stub(x => x.FooLikeObject1).Return("AValidString"); 
stub.Stub(x => x.FooLikeObject2).Return("AValidString2"); 
stub.Stub(x => x.FooLikeObject5).Return("1"); 
stub.Stub(x => x.FooLikeObject6).Return("1"); 
+0

是的。這正是我在'CreateBasicIFooLikeObjectStub()'方法中所做的。問題是在我的測試方法中,我可能想調用'stub.Stub(x => x.FooLikeObject2).Return(null);'以驗證在這種情況下引發異常。那是當我得到上面詳述的InvalidOperationException。我會編輯這個問題來說明清楚。 – 2009-11-02 20:47:18

+0

@勞倫斯哦,我明白你在說什麼了。在這種情況下,您需要做的是實際創建兩個不同的存根實例,並讓它們具有不同的值集合。 – Joseph 2009-11-02 20:54:03