我如何模拟私人领域?

我真的很嘲笑我正在尝试用模拟对象替换私有字段。 目前,私有字段的实例是在构造函数中创建的。 我的代码看起来像……

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)的unit testing从ISnapshot.FreezeFrom(IUpdates)中调用。 我猜我应该用模拟对象替换私有字段_latest_snapshot (可能是错误的假设?)。 如何在保留无参数构造函数的同时不使用LatestSnapshot设置公开?

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

ISnapshot.FreezeFrom本身的实际实现使用深度对象图调用其他方法的层次结构,所以我不太热衷于断言对象图。

提前致谢。

我几乎引用了“有效使用遗留代码”的技巧:

  1. 在unit testing中对您的类进行子类化,并用其中的模拟对象取代您的私有变量(通过添加公共setter或在构造函数中)。 您可能必须使变量受到保护。
  2. 为此私有变量创建受保护的getter,并在测试子类中覆盖它以返回模拟对象而不是实际的私有变量。
  3. 创建用于创建ISnapshot对象的受保护工厂方法,并在测试子类中覆盖它以返回模拟对象的实例而不是实际对象的实例。 这样构造函数将从一开始就获得正确的值。
  4. 参数化构造函数以获取ISnapshot的实例。

我认为你不需要模拟私有成员变量。 是不是嘲笑对象的公共接口按预期工作的整个想法? 私有变量是模拟不关心的实现细节。

我不确定你能做到这一点。 如果您想测试_next那么您可能不得不将其作为参数传递,然后在unit testing中传递Mock对象,然后您可以使用Expectation进行测试。 如果我在Moq尝试这样做,那就是我要做的事情。

作为我可能尝试使用Moq框架的示例:

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

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

这个答案可能很简单,但是看一下代码,有没有什么方法可以调用ISnapshot.FreezeFrom(IUpdates) ? 听起来你想断言一直都是真的。

正如Jason所说,mocking适用于你的类依赖于SomeInterface来完成它的工作,并且你希望独立于你在运行时实际使用的SomeInterface任何实现来测试YourClass

要问的问题是:如果有效,外部可见效果是什么?

所有这些快照会发生什么? 一个选项可能是使用来自外部的第一个快照来初始化Cache,比如在构造函数中。 另一个可能是模拟Snapshot调用在缓存之外重要的任何内容。 这取决于你关心的事情。

回应可能为时已晚。 无论如何。 我也有类似的问题。

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

我需要在我的测试用例中设置XYZ的值。 我使用这个syntex解决了这个问题。

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

在上面的例子中,我们可以这样做

 Expect.Call(_cache.LatestSnapshot).Return(new Snapshot()); _repository.ReplayAll(); 

您可能必须像这样重构您的类,以便为ISnapshot注入不同的依赖项。 你的class级将保持相同的function。

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

您可以使用模拟的类实例将“setSnapshot(ISnapshot)”方法添加到Cache中。

您还可以添加一个带有ISnapshot的构造函数。

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

 template  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 bar; 

在测试代​​码中做:

 Cache mockFoo;