在上一节上我们看到一个示例。在这边我们要学习如何对各种形式的方法进行Mock和验证。
public interface ISettingService
{
StudentSetting GetStudentSetting(string name);
void GetStudentSettingOut(out StudentSetting setting);
void GetStudentSettingRef(ref StudentSetting setting);
T Get<T>(string name);
}
public class StudentSetting
{
public int MaxAge { get; set; }
public string Name { get; set; }
}
// 带ref参数需要这个委托
delegate void refCallback(ref StudentSetting setting);
[Fact]
public void Test_Method_Examples()
{
var studentSetting = new StudentSetting()
{
MaxAge = 1
};
//普通方法
var settingService = new Mock<ISettingService>();
settingService.Setup(x => x.GetStudentSetting("aa")).Returns(studentSetting);
settingService.Object.GetStudentSetting("aa").Should().Be(studentSetting);
settingService.Verify(x => x.GetStudentSetting("aa"), Times.Once);
//泛型方法
settingService.Setup(x => x.Get<StudentSetting>("aa")).Returns(studentSetting);
settingService.Object.Get<StudentSetting>("aa").Should().Be(studentSetting);
settingService.Verify(x => x.Get<StudentSetting>("aa"), Times.AtLeastOnce);
//带out参数
StudentSetting outStudentSetting = new StudentSetting() { MaxAge = 2, Name = DateTime.Now.Ticks.ToString() };
settingService.Setup(x => x.GetStudentSettingOut(out outStudentSetting));
settingService.Object.GetStudentSettingOut(out StudentSetting temp);
temp.Should().Be(outStudentSetting);
settingService.Verify(it => it.GetStudentSettingOut(out outStudentSetting), Times.AtLeastOnce);
//带ref参数, 需要创建的委托 refCallback
settingService.Setup(x => x.GetStudentSettingRef(ref It.Ref<StudentSetting>.IsAny))
.Callback(new refCallback((ref StudentSetting setting) => {
setting.MaxAge = 4;
}));
StudentSetting temp2 = new StudentSetting() { MaxAge = 3, Name = "ref" };
settingService.Object.GetStudentSettingRef(ref temp2);
temp2.MaxAge.Should().Be(4);
temp2.Name.Should().Be("ref");
settingService.Verify(it => it.GetStudentSettingRef(ref It.Ref<StudentSetting>.IsAny), Times.Exactly(1));
//跟据参数,动态返回需要的值
settingService.Setup(x => x.GetStudentSetting(It.IsAny<string>()))
.Returns<string>(name =>
{
return new StudentSetting() { Name = name };
});
settingService.Object.GetStudentSetting("bb").Name.Should().Be("bb");
//每次调用返回不同的值
settingService.SetupSequence(x => x.GetStudentSetting("cc"))
.Returns(new StudentSetting() { MaxAge = 3 })
.Returns(new StudentSetting() { MaxAge = 4 })
//这中间也是可以插入 exception的
.Returns(new StudentSetting() { MaxAge = 5 });
settingService.Object.GetStudentSetting("cc").MaxAge.Should().Be(3);
settingService.Object.GetStudentSetting("cc").MaxAge.Should().Be(4);
settingService.Object.GetStudentSetting("cc").MaxAge.Should().Be(5);
settingService.Verify(it => it.GetStudentSetting("cc"), Times.Exactly(3));
//抛出异常
settingService.Setup(x => x.GetStudentSetting("ex")).Throws(new ArgumentException("ex"));
Assert.Throws<ArgumentException>(() => settingService.Object.GetStudentSetting("ex"));
settingService.Verify(it => it.GetStudentSetting("ex"), Times.Once);
//在被回调的时候做一些事情,可以把验证直接放在这边
settingService.Setup(x => x.GetStudentSetting(It.IsAny<string>())).Callback<string>((name) =>
{
name.Should().Be("callback");
});
settingService.Object.GetStudentSetting("callback");
}
在验证函数被调用的时候,我们可以看到有一个类Times,通过这个我们可以用来判定这个函数的调用次数。
我们也可以在Mock的时候对方法的参数进行匹配
[Fact]
public void Count_Should_Return_Suitable_Quantity()
{
var studentSetting = new StudentSetting()
{
MaxAge = 1
};
var settingService = new Mock<ISettingService>();
//通过使用 is 我们可能 写出自己想要的条件
settingService.Setup(x => x.GetStudentSetting(It.Is<string>(x => x.Contains("aa")))).Returns(studentSetting);
settingService.Object.GetStudentSetting("aa").Should().Be(studentSetting);
settingService.Verify(x => x.GetStudentSetting("aa"), Times.Once);
}
public interface ISettingService
{
string Name { get; set; }
Abc Abc { get; }
}
public class Abc
{
// 类里如果不定义成virtual Moq没有办法重写它
public virtual string Name2 { get; set; }
}
[Fact]
public void Test_Properties()
{
var settingService = new Mock<ISettingService>();
settingService.SetupGet(x => x.Name).Returns("abc");
settingService.Object.Name.Should().Be("abc");
settingService.SetupGet(x => x.Abc.Name2).Returns("abc2");
settingService.Object.Abc.Name2.Should().Be("abc2");
}