有时候我们的系统当中很多是旧代码,或者其它的原因,我们的类依赖的不是接口(抽象类)而是具体类。 这个时候我们希望对它进行Mock的话,我们就需要把它的方法加上virtual
public class SettingService
{
public virtual StudentSetting GetStudentSetting(string name)
{
return new StudentSetting() { };
}
}
public class StudentSetting
{
public int MaxAge { get; set; }
public string Name { get; set; }
}
[Fact]
public void Test_Class()
{
var studentSetting = new StudentSetting()
{
MaxAge = 1
};
var settingService = new Mock<SettingService>();
settingService.Setup(x => x.GetStudentSetting("aa")).Returns(studentSetting);
settingService.Object.GetStudentSetting("aa").Should().Be(studentSetting);
settingService.Verify(x => x.GetStudentSetting("aa"), Times.Once);
}
public class SettingService
{
public readonly int Age;
public SettingService(int age)
{
this.Age = age;
}
}
[Fact]
public void Test_Class()
{
// 有几个参数,这边就要加上几个参数。我们的例子是一个参数,所以这边只需要一个
var settingService = new Mock<SettingService>(10);
}
public class SettingService
{
public string A1()
{
return "a1" + A2() + A3();
}
//注意 有 virtual
public virtual string A2()
{
return "a2";
}
//注意 没有 virtual
public string A3()
{
return "a3";
}
}
[Fact]
public void Test_Class()
{
var settingService = new Mock<SettingService>();
// a2 方法默认被moq重写掉了。所以返回了a1a3
settingService.Object.A1().Should().Be("a1a3");
var settingService2 = new Mock<SettingService>()
{
CallBase = true
};
//使用callbase,没有重写的调用原生的方法
settingService2.Object.A1().Should().Be("a1a2a3");
var settingService3 = new Mock<SettingService>()
{
CallBase = true
};
//mock了a2方法, callbase对此无效了
settingService3.Setup(x => x.A2()).Returns("b2");
settingService3.Object.A1().Should().Be("a1b2a3");
}
因为 protected方法也是可以被子类重写的。所以我们也是可以对它进行Mock.
public class SettingService
{
public string AA(string name)
{
return "AA:" + A1(name);
}
protected virtual string A1(string name)
{
return "A1:" + name;
}
}
using FluentAssertions;
using Moq;
using Moq.Protected;
using Xunit;
namespace MyFirstUnitTests
{
public class StudentServiceTest
{
[Fact]
public void Test_Protected()
{
var settingService = new Mock<SettingService>();
//需要引用Moq.Protected;
settingService.Protected().Setup<string>("A1", ItExpr.IsAny<string>()).Returns("qqq");
settingService.Object.AA("sss").Should().Be("AA:qqq");
}
}
}
有时有一些方法是用internal来修饰的。 这个时候我们可以用InternalsVisibleToAttribute。 最好是加在项目AssemblyInfo.cs哪边。这样整个项目都是有效果
[assembly: InternalsVisibleToAttribute("projectName")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] //这个是Moq的namespace