我正在使用moq.dll 当我模拟一个类(所有IRepository接口)时,我使用这个行代码
int state = 5;
var rep = new Mock<IRepository>();
rep.Setup(x => x.SaveState(state)).Returns(true);
IRepository repository = rep.Object;
但是在这种情况下我模拟了存储库类中的所有函数。 然后,类库中的所有方法都被Mock dll的方法设置替换
我想使用类库中定义的所有方法(真正的类)并且只模拟一个函数(SaveState)
我该怎么做?有可能吗?
答案 0 :(得分:20)
您可以创建真实存储库的实例,然后使用As<>()
获取所需的界面,然后您可以使用设置覆盖该界面,如下所示:
var mockRep = new Mock<RealRepository>(ctorArg1, ctorArg2, ...)
.As<IRepository>();
mockRep.Setup(x => x.SaveState(state)).Returns(true);
然后mockRep.Object
作为被测试类的存储库依赖项。
请注意,您只能以这种方式在Interface
*或虚拟方法上模拟方法。
更新:*这可能不适用于所有情况,因为.Setup
仅适用于虚拟方法,而C#接口实现仅{{3} } "virtual" and sealed。使用As()
将阻止部分模拟行为。
所以似乎RealRepository
具体类需要用虚方法实现IRepository
接口才能使部分模拟成功,在这种情况下CallBase
可用于电汇。
public interface IRepo
{
string Foo();
string Bar();
}
public class RealRepo : IRepo
{
public RealRepo(string p1, string p2) {Console.WriteLine("CTOR : {0} {1}", p1, p2); }
// ** These need to be virtual in order for the partial mock Setups
public virtual string Foo() { return "RealFoo"; }
public virtual string Bar() {return "RealBar"; }
}
public class Sut
{
private readonly IRepo _repo;
public Sut(IRepo repo) { _repo = repo; }
public void DoFooBar()
{
Console.WriteLine(_repo.Foo());
Console.WriteLine(_repo.Bar());
}
}
[TestFixture]
public class SomeFixture
{
[Test]
public void SomeTest()
{
var mockRepo = new Mock<RealRepo>("1st Param", "2nd Param");
// For the partially mocked methods
mockRepo.Setup(mr => mr.Foo())
.Returns("MockedFoo");
// To wireup the concrete class.
mockRepo.CallBase = true;
var sut = new Sut(mockRepo.Object);
sut.DoFooBar();
}
}
答案 1 :(得分:1)
我来到此页面是因为我遇到了完全相同的问题:我需要模拟一个方法,该方法依赖于许多外部源,并且可以产生三个输出之一,而让类的其余部分来工作。不幸的是,上面提出的部分模拟方法无效。我真的不知道为什么为什么不起作用。但是,主要问题是,即使将断点放在所需的位置,也无法在此类模拟类中进行调试。这不好,因为您可能真的需要调试某些东西。
因此,我使用了一个简单得多的解决方案:声明要模拟为虚拟的所有方法。然后从该类继承并编写单线模拟重写以返回所需的内容,例如:
public class Repository
{
/// <summary>
/// Let's say that SaveState can return true / false OR throw some exception.
/// </summary>
public virtual bool SaveState(int state)
{
// Do some complicated stuff that you don't care about but want to mock.
var result = false;
return result;
}
public void DoSomething()
{
// Do something useful here and assign a state.
var state = 0;
var result = SaveState(state);
// Do something useful with the result here.
}
}
public class MockedRepositoryWithReturnFalse : Repository
{
public override bool SaveState(int state) => false;
}
public class MockedRepositoryWithReturnTrue : Repository
{
public override bool SaveState(int state) => true;
}
public class MockedRepositoryWithThrow : Repository
{
public override bool SaveState(int state) =>
throw new InvalidOperationException("Some invalid operation...");
}
仅此而已。然后,您可以在单元测试期间使用模拟的存储库,并且可以调试所需的任何内容。您甚至可以将保护级别置于公开之下,以免暴露您不想公开的内容。