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

如何模拟私人场地?

  •  21
  • Fung  · 技术社区  · 17 年前

    public class Cache {
        private ISnapshot _lastest_snapshot;
    
        public ISnapshot LatestSnapshot {
            get { return this._lastest_snapshot; }
            private set { this._latest_snapshot = value; }
        }
    
        public Cache() {
            this.LatestSnapshot = new Snapshot();
        }
    
        public void Freeze(IUpdates Updates) {
            ISnapshot _next = this.LastestSnapshot.CreateNext();
            _next.FreezeFrom(Updates);
            this.LastestSnapshot = _next;
        }
    
    }
    

    ISnapshot.FreezeFrom(IUpdates) 从内部调用 Cache.Freeze(IUpdates) 我想我应该替换私人字段 _latest_snapshot LatestSnapshot

    如果我完全打算以错误的方式编写测试,那么请也指出。

    实际执行情况 ISnapshot.FreezeFrom

    9 回复  |  直到 17 年前
        1
  •  26
  •   Alex B    17 年前

    我几乎引用了以下技术 "Working Effectively with Legacy Code" :

    1. 在单元测试中将类子类化,并在其中用模拟对象替换私有变量(通过添加公共设置器或构造函数)。您可能必须使变量受到保护。
    2. 为这个私有变量创建一个受保护的getter,并在测试子类中重写它,以返回一个模拟对象而不是实际的私有变量。
    3. 创建用于创建的受保护工厂方法 ISnapshot 对象,并在测试子类中重写它,以返回模拟对象的实例而不是真实对象。这样,构造函数将从一开始就得到正确的值。
    4. 参数化构造函数以获取以下实例 ISnapshot .
        2
  •  3
  •   mezoid    17 年前

    我不确定你能不能做到。如果你想测试 _next 那么,您可能需要将其作为参数传递,然后在单元测试中传递一个Mock对象,然后可以使用Expectation对其进行测试。如果我想在莫克做这件事,我会这样做。

    作为我可能尝试使用Moq框架的一个例子:

    Mock<ISnapshot> snapshotMock = new Mock<ISnapshot>();
    snapshotMock.Expect(p => p.FreezeFrom(expectedUpdate)).AtMostOnce();
    Cache c = new Cache(snapshotMock.Object);
    c.Freeze(expectedUpdate);
    

    注意:我没有尝试编译上面的代码。这只是为了举例说明我将如何解决这个问题。

        3
  •  2
  •   Jason    17 年前

        4
  •  1
  •   matt b    17 年前

    这个答案可能很简单,但看看代码,有什么方法可以 ISnapshot.FreezeFrom(IUpdates) 不会被召唤吗?听起来你想断言一些永远正确的事情。

    正如杰森所说,嘲笑是指你的班级依赖于 SomeInterface 做这项工作,你想测试 YourClass 与任何实施隔离 一些接口 您实际上在运行时使用。

        5
  •  1
  •   Steve Freeman    17 年前

    要问的问题是:如果这种方法奏效,外部可见的影响是什么?

        6
  •  1
  •   user231038    16 年前

    现在回应可能为时已晚。不管怎样。我也有类似的问题。

    public class Model
    {
      public ISomeClass XYZ{
          get;
          private set;
          }
    }
    

    我需要在测试用例中设置XYZ的值。我用这种合成纤维解决了这个问题。

    Expect.Call(_model.XYZ).Return(new SomeClass());
    _repository.ReplayAll();
    

    在上述情况下,我们可以这样做

    Expect.Call(_cache.LatestSnapshot).Return(new Snapshot());
    _repository.ReplayAll();
    
        7
  •  0
  •   murki    15 年前

    您可能必须像这样重构您的类,以便为其注入不同的ISnapshot依赖关系。你的班级将保持不变。

    public class Cache {
     private ISnapshot _lastest_snapshot;
    
     public ISnapshot LatestSnapshot {
      get { return this._lastest_snapshot; }
      private set { this._latest_snapshot = value; }
     }
    
     public Cache() : this (new Snapshot()) {
     }
    
     public Cache(ISnapshot latestSnapshot) {
      this.LatestSnapshot = latestSnapshot;
     }
    
     public void Freeze(IUpdates Updates) {
      ISnapshot _next = this.LastestSnapshot.CreateNext();
      _next.FreezeFrom(Updates);
      this.LastestSnapshot = _next;
     }
    
    }
    
        8
  •  0
  •   Vanuan tacaswell    15 年前

    您可以简单地将“setSnapshot(ISnapshot)”方法添加到带有模拟类实例的Cache中。

    您还可以添加一个接受ISnapshot的构造函数。

        9
  •  -3
  •   brainimus user417509    15 年前

    将缓存转换为模板,如下所示。

    template <typename T=ISnapshot>
    public class Cache {
        private T _lastest_snapshot;
    
        public T LatestSnapshot {
            get { return this._lastest_snapshot; }
            private set { this._latest_snapshot = value; }
        }
    
        public Cache() {
            this.LatestSnapshot = new Snapshot();
        }
    
        public void Freeze(IUpdates Updates) {
            T _next = this.LastestSnapshot.CreateNext();
            _next.FreezeFrom(Updates);
            this.LastestSnapshot = _next;
        }
    
    }
    

    在生产代码中,请执行以下操作:

    Cache<> foo;//OR
    Cache<ISnapshot> bar;
    

    Cache<MockSnapshot> mockFoo;