代码之家  ›  专栏  ›  技术社区  ›  Redwood

如何在不重置整个存根的情况下重置存根中属性的结果?

  •  1
  • Redwood  · 技术社区  · 15 年前

    我不懂犀牛戏法,所以我可能完全错过了一些东西。

    假设我有一个接口,它有六个属性:

    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");
    }
    

    这对于测试foo3和foo4来说已经足够好了,但是当测试foo1、2、5或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); });
    }
    

    如何设置它,以便我可以重写已经设置了返回值的单个属性,而不必重新执行所有其他属性?

    2 回复  |  直到 15 年前
        1
  •  1
  •   Redwood    15 年前

    可以使用 Repeat.Any() 构建。

    我没有使用SETUPRESULT对此进行测试。对于语法,它与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); });
    }
    

    我唯一要注意的是你不能两次这样做。

        2
  •  0
  •   Joseph    15 年前

    我可能错过了什么,但你试过这么做吗?

    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");