C# 使用Autofac为同一类中的内部方法编写Moq单元测试
我正在同一个类中尝试模拟内部方法,但模拟失败 这是我的密码 接口C# 使用Autofac为同一类中的内部方法编写Moq单元测试,c#,unit-testing,nunit,moq,autofac,C#,Unit Testing,Nunit,Moq,Autofac,我正在同一个类中尝试模拟内部方法,但模拟失败 这是我的密码 接口 public interface IStudentService { int GetRank(int studentId); IList<Subject> GetSubjects(int studentId); } 公共接口IStudentService { int GetRank(int studentId); IList GetSubjects(国际学生ID); } 实施 public clas
public interface IStudentService
{
int GetRank(int studentId);
IList<Subject> GetSubjects(int studentId);
}
公共接口IStudentService
{
int GetRank(int studentId);
IList GetSubjects(国际学生ID);
}
实施
public class StudentService : IStudentService
{
private readonly IStudentRepository _studentRepository;
private readonly ISubjectRepository _subjectRepository;
public StudentService(IStudentRepository studentRepository, ISubjectRepository subjectRepository)
{
_studentRepository = studentRepository;
_subjectRepository = subjectRepository;
}
public int GetRank(int studentId)
{
IList<Subject> subjects = GetSubjects(studentId);
int rank = 0;
//
//Calculate Rank
//
return rank;
}
public virtual IList<Subject> GetSubjects(int studentId)
{
return _subjectRepository.GetAll(studentId);
}
}
公共班级学生服务:IStudentService
{
私人只读是学生档案库(studentRepository);
私有只读ISubjectRepository_subjectRepository;
公共学生服务(IStudentRepository studentRepository,ISubjectRepository subjectRepository subjectRepository)
{
_studentRepository=studentRepository;
_subjectRepository=subjectRepository;
}
公共int GetRank(int studentId)
{
IList受试者=获取受试者(studentId);
int秩=0;
//
//计算等级
//
返回等级;
}
公共虚拟IList GetSubjects(int studentId)
{
返回_subjectRepository.GetAll(studentId);
}
}
单元测试
[TestFixture]
public class StudentServiceTest
{
[SetUp]
public void Setup()
{
}
[TearDown]
public void TearDown()
{
}
[Test]
public void GetRankTest()
{
using (var mock = AutoMock.GetStrict())
{
var mockStudentService = new Mock<IStudentService>();
mockStudentService.Setup(x => x.GetSubjects(1)).Returns(new ServiceResponse<SystemUser>(new List<Subject>{ new AccounProfile(), new AccounProfile()}));
mock.Provide(mockStudentService.Object);
var component = mock.Create<StudentService>();
int rank = component.GetRank(1);
mockStudentService.VerifyAll();
Assert.AreEqual(1, rank, "GetRank method fails");
}
}
}
[TestFixture]
公共班级学生服务测试
{
[设置]
公共作废设置()
{
}
[撕裂]
公共无效拆卸()
{
}
[测试]
public void GetRankTest()
{
使用(var mock=AutoMock.GetStrict())
{
var mockStudentService=new Mock();
mockStudentService.Setup(x=>x.GetSubjects(1)).Returns(新服务响应(新列表{new accountupfile(),new accountupfile()}));
Provide(mockStudentService.Object);
var component=mock.Create();
int-rank=component.GetRank(1);
mockStudentService.VerifyAll();
AreEqual(1,rank,“GetRank方法失败”);
}
}
}
当我调试代码时,它不是在模仿GetSubjects方法。事实上,它深入到了这个方法中。我正在使用Nunit、Moq和Autofac编写单元测试
提前谢谢 我想您的
GetSubjects
方法必须声明为虚拟的,否则它不能被模仿
public virtual IList<Subject> GetSubjects(int studentId)
{
// code here
}
public虚拟IList GetSubjects(int studentId)
{
//代码在这里
}
有两种解决方案
1.部分嘲弄
在这种方法中,您为正在测试的组件创建模拟(StudentService
),并告诉Moq模拟它的一些方法(GetSubjects
——要模拟的方法必须是虚拟的),同时将其他(GetRank
)委托给:
设置mock.CallBase=true
指示Moq将任何与显式Setup
调用不匹配的调用委托给其基本实现
此代码适用于。谢谢大家的支持
[TestFixture]
public class StudentServiceTest
{
private Mock<StudentRepository> _studentRepositoryMock;
private Mock<SubjectRepository> _subjectRepositoryMock;
private Mock<StudentService> _studentServiceMock;
[SetUp]
public void Setup()
{
_studentRepositoryMock = new Mock<StudentService>(MockBehavior.Strict);
_subjectRepositoryMock = new Mock<SubjectRepository>(MockBehavior.Strict);
_studentServiceMock = new Mock<StudentService>(_studentRepositoryMock.Object, _subjectRepositoryMock.Object);
_studentServiceMock.CallBase = true;
}
[TearDown]
public void TearDown()
{
}
[Test]
public void GetRankTest()
{
_studentServiceMock.Setup(x => x.GetSubjects(1)).Returns(...);
int rank = component.GetRank(1);
_studentServiceMock.VerifyAll();
Assert.AreEqual(1, rank, "GetRank method fails");
}
}
[TestFixture]
公共班级学生服务测试
{
私人模拟(studentRepositoryMock),;
私人模拟(subject repositorymock);;
私人模拟——学生服务模拟;
[设置]
公共作废设置()
{
_studentRepositoryMock=newmock(MockBehavior.Strict);
_subjectRepositoryMock=新模拟(MockBehavior.Strict);
_studentServiceMock=新建Mock(_studentRepositoryMock.Object,_subjectRepositoryMock.Object);
_studentServiceMock.CallBase=true;
}
[撕裂]
公共无效拆卸()
{
}
[测试]
public void GetRankTest()
{
_studentServiceMock.Setup(x=>x.GetSubjects(1))。返回(…);
int-rank=component.GetRank(1);
_studentServiceMock.VerifyAll();
AreEqual(1,rank,“GetRank方法失败”);
}
}
既然可以轻松模拟存储库,为什么还要尝试模拟内部方法?Jimmy说得对:)如果GetSubject方法有多个存储库方法,那么我必须模拟它们。此外,如果GetSubjects方法有来自同一类的另一个方法,我也必须模拟它们。因此,除了我正在测试的方法之外,我还必须模拟很多东西。Autofac是否支持部分mokcing?首先,Autofac是一个DI框架,与mocking完全无关。在这里的示例中,您可以删除Autofac的所有痕迹,并且仍然能够使用模拟编写测试。事实上,我总是使用尽可能少的额外框架编写测试:新建一个StudentService
实例,并传入两个模拟存储库。是的,当测试一段代码时,您必须模拟外部依赖项,在您的例子中是存储库。如果您觉得正在进行的工作太多,那么这可能是您的服务做得太多的一个迹象:将其拆分为更细粒度的服务!。。。建议:阅读更多关于模拟的内容,例如,这个线程很好,我将该方法设置为虚拟,并使用CallBase=true进行了尝试,但没有成功:(在第二个解决方案中,如果GetSubject方法有多个存储库方法,那么我必须全部模拟它们。此外,如果GetSubjects方法有来自同一类的另一个方法,我也必须模拟它们。因此,除了我正在测试的方法之外,我还必须模拟很多东西。解决方案是什么?
using (var mock = AutoMock.GetStrict())
{
var subjectRepositoryMock = new Mock<ISubjectRepository>();
subjectRepositoryMock.Setup(x => x.GetSubjects(1)).Returns(...);
mock.Provide(subjectRepositoryMock.Object);
var component = mock.Create<StudentService>();
int rank = component.GetRank(1);
// verify is not needed once again
Assert.AreEqual(1, rank, "GetRank method fails");
}
[TestFixture]
public class StudentServiceTest
{
private Mock<StudentRepository> _studentRepositoryMock;
private Mock<SubjectRepository> _subjectRepositoryMock;
private Mock<StudentService> _studentServiceMock;
[SetUp]
public void Setup()
{
_studentRepositoryMock = new Mock<StudentService>(MockBehavior.Strict);
_subjectRepositoryMock = new Mock<SubjectRepository>(MockBehavior.Strict);
_studentServiceMock = new Mock<StudentService>(_studentRepositoryMock.Object, _subjectRepositoryMock.Object);
_studentServiceMock.CallBase = true;
}
[TearDown]
public void TearDown()
{
}
[Test]
public void GetRankTest()
{
_studentServiceMock.Setup(x => x.GetSubjects(1)).Returns(...);
int rank = component.GetRank(1);
_studentServiceMock.VerifyAll();
Assert.AreEqual(1, rank, "GetRank method fails");
}
}