使用Autofac为同一类中的内部方法编写Moq单元测试
本文关键字:方法 内部 单元测试 Moq 一类 Autofac 使用 | 更新日期: 2023-09-27 18:28:56
我正在同一个类中尝试mock内部方法。但我的嘲笑失败了。
这是我的密码。
接口
public interface IStudentService
{
int GetRank(int studentId);
IList<Subject> GetSubjects(int studentId);
}
实施
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);
}
}
单元测试
[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");
}
}
}
当我调试代码时,它并不是在嘲笑GetSubjects方法。它实际上进入了这种方法的内部。我正在使用Nunit、Moq和Autofac编写单元测试。
提前感谢!
有两种解决方案。
1.部分嘲讽
在这种方法中,您创建正在测试的组件的mock(StudentService
),并告诉Moq对其某些方法进行mock(要mock的GetSubjects
-方法必须是虚拟的),同时将其他方法(GetRank
)委托给基本实现:
设置
mock.CallBase = true
指示Moq将任何与显式Setup
调用不匹配的调用委派给其基本实现。
// mockStudentService is not needed, we use partial mock
var service = mock.Create<StudentService>();
service.CallBase = true;
service.Setup(m => m.GetSubjects(1)).Returns(...);
var rank = service.GetRank(1);
// you don't need .VerifyAll call, you didn't not set any expectations on mock
Assert.AreEqual(1, rank, "GetRank method fails");
2.模拟内部服务(ISubjectRepository
)
为特殊情况保留部分实物模型。你的情况很常见。您的组件(StudentService
)可以依靠模拟的ISubjectRepository
为其提供主题,而不是嘲笑自己:
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");
}
}
我想您的GetSubjects
方法必须声明为virtual,否则它将无法被嘲笑。
public virtual IList<Subject> GetSubjects(int studentId)
{
// code here
}