最小起订量单元测试 c# class 库项目的最佳方式
Best way to moq unit test c# class library project
SalaryManager class 有一个名为 DoCalculation 的方法,它调用使用工厂模式实现的 GetSum 方法。除了调用 GetSum 方法之外,DoCalculation 方法还执行一些其他操作。我想通过模拟对 GetSum() 的调用来对 DoCalculation 方法进行单元测试。有人可以建议在最小起订量模拟中实现它的最佳方法吗?下面是示例代码,
interface ICalc
{
int GetSum(int a, int b);
}
class NormalCalc : ICalc
{
public int GetSum(int a,int b)
{
return a + b;
}
}
class SumFactory
{
public static ICalc GetSumObject(int option)
{
if (option == 1)
return new NormalCalc();
return null;
}
}
class SalaryManager
{
private static ICalc CalcRef = SumFactory.GetSumObject(1);
public int DoCalculation(int a, int b)
{
int Sum=CalcRef.GetSum(a, b);
//Perform some other operation
//
//
}
}
不要使用静态工厂方法。将工厂 class 转换为可注入 service/interface 并将其注入到被测系统中。
public interface ISumFactory {
ICalc GetSumObject(int option);
}
public class SumFactory : ISumFactory {
public ICalc GetSumObject(int option) {
if (option == 1)
return new NormalCalc();
return null;
}
}
public class SalaryManager {
private ICalc CalcRef;
public SalaryManager(ISumFactory factory) {
CalcRef = factory.GetSumObject(1);
}
public int DoCalculation(int a, int b) {
int Sum = CalcRef.GetSum(a, b);
//Perform some other operation
//
//
//...;
}
}
然后模拟依赖项以测试和验证预期。
[TestClass]
public class MyTestClass {
[TestMethod]
public void MyTestMethod() {
//Arrange
var calcMock = new Mock<ICalc>();
calcMock.Setup(m => m.GetSum(It.IsAny<int>(), It.IsAny<int>()))
.Returns((int a, int b) => a + b)
.Verifiable();
var factoryMock = new Mock<ISumFactory>();
factoryMock.Setup(m => m.GetSumObject(1)).Returns(calcMock.Object)
.Verifiable();
var sut = new SalaryManager(factoryMock.Object);
//Act
var result = sut.DoCalculation(1, 1);
//Assert
//...
factoryMock.Verify();
calcMock.Verify();
}
}
为了模拟 GetSum 方法,您需要以某种方式将 ICalc 依赖项注入 SalaryManager class。
尽管 SalaryManager 使用工厂创建 ICalc 并且它本身并不够好,工厂方法本身是静态方法,return是一个具体的 class,您无法更改它被 return 模拟 class 而不是因为它是一个静态方法,因此根据这个设计,即使你的单元测试也必须使用 NormalCalc 作为 Icalc 实现。
你基本上有两个选择:
通过其构造函数将 ICalc 直接注入 SalaryManager:
public class SalaryManager
{
private readonly ICalc _calc;
public SalaryManager(ICalc clac)
{
_calc = calc;
}
public int DoCalculation(int a, int b)
{
int Sum = _calc.GetSum(a, b);
//...
}
}
现在很容易将模拟的 ICalc 实例注入到您的 class,
只需使用 moq 创建 ICalc 的模拟并将其传递给 calss
通过构造函数。
如果您仍想使用工厂(这似乎
根据它的作用,在你的情况下非常无用,作为旁注,我倾向于在使用 DI 时使用工厂,只有当 class 依赖于一个我不想为 [= 保持活动状态的 IDisposable 对象时38=]的整个生命时间)就是要改变
它从静态方法到将实现一个具体工厂
接口:
public interface ISumFactory
{
ICalc GetCalc(int option);
}
public SumFactory : ISumFactory
{
public ICalc GetCalc(int option)
{
if (option == 1)
return new NormalCalc();
return null;
}
}
现在你应该将工厂接口注入 SalaryManager class
通过它的构造函数并在需要时使用它:
public class SalaryManager
{
private readonly ICalcFacotry _calcFactory;
public SalaryManager(ICalcFacotry clacFacotry)
{
_calcFactory = clacFacotry;
}
public int DoCalculation(int a, int b)
{
ICalc calc = _calcFactory.GetCalc(1);
int Sum = calc.GetSum(a, b);
//...
}
}
现在在你的单元测试中你可以创建 ICalcFacotry mock 并将其传递给你的 class,你应该将模拟的 facotry 设置为 return 当使用 facotry 方法时使用 1 作为 ICalc mock选项.
您可以在不更改源代码的情况下对该方法进行单元测试。
通过使用 Typmock Isolator,您将能够在 class 创建之前模拟它的未来实例,因此当您模拟 Iclac
的未来实例时,它将模拟所有 classes 实现了这个接口。
例如:
[TestMethod]
public void TestMethod()
{
//mock the future instances of Iclac
//and when the next NormalClac will be created it will be mocked as well
var fakeIclac = Isolate.Fake.NextInstance<ICalc>();
//setting the behavior of GetSum
Isolate.WhenCalled(() => fakeIclac.GetSum(0, 0)).WillReturn(5);
var result = new SalaryManager().DoCalculation(0, 0);
Assert.AreEqual(5, result);
}
SalaryManager class 有一个名为 DoCalculation 的方法,它调用使用工厂模式实现的 GetSum 方法。除了调用 GetSum 方法之外,DoCalculation 方法还执行一些其他操作。我想通过模拟对 GetSum() 的调用来对 DoCalculation 方法进行单元测试。有人可以建议在最小起订量模拟中实现它的最佳方法吗?下面是示例代码,
interface ICalc
{
int GetSum(int a, int b);
}
class NormalCalc : ICalc
{
public int GetSum(int a,int b)
{
return a + b;
}
}
class SumFactory
{
public static ICalc GetSumObject(int option)
{
if (option == 1)
return new NormalCalc();
return null;
}
}
class SalaryManager
{
private static ICalc CalcRef = SumFactory.GetSumObject(1);
public int DoCalculation(int a, int b)
{
int Sum=CalcRef.GetSum(a, b);
//Perform some other operation
//
//
}
}
不要使用静态工厂方法。将工厂 class 转换为可注入 service/interface 并将其注入到被测系统中。
public interface ISumFactory {
ICalc GetSumObject(int option);
}
public class SumFactory : ISumFactory {
public ICalc GetSumObject(int option) {
if (option == 1)
return new NormalCalc();
return null;
}
}
public class SalaryManager {
private ICalc CalcRef;
public SalaryManager(ISumFactory factory) {
CalcRef = factory.GetSumObject(1);
}
public int DoCalculation(int a, int b) {
int Sum = CalcRef.GetSum(a, b);
//Perform some other operation
//
//
//...;
}
}
然后模拟依赖项以测试和验证预期。
[TestClass]
public class MyTestClass {
[TestMethod]
public void MyTestMethod() {
//Arrange
var calcMock = new Mock<ICalc>();
calcMock.Setup(m => m.GetSum(It.IsAny<int>(), It.IsAny<int>()))
.Returns((int a, int b) => a + b)
.Verifiable();
var factoryMock = new Mock<ISumFactory>();
factoryMock.Setup(m => m.GetSumObject(1)).Returns(calcMock.Object)
.Verifiable();
var sut = new SalaryManager(factoryMock.Object);
//Act
var result = sut.DoCalculation(1, 1);
//Assert
//...
factoryMock.Verify();
calcMock.Verify();
}
}
为了模拟 GetSum 方法,您需要以某种方式将 ICalc 依赖项注入 SalaryManager class。
尽管 SalaryManager 使用工厂创建 ICalc 并且它本身并不够好,工厂方法本身是静态方法,return是一个具体的 class,您无法更改它被 return 模拟 class 而不是因为它是一个静态方法,因此根据这个设计,即使你的单元测试也必须使用 NormalCalc 作为 Icalc 实现。
你基本上有两个选择:
通过其构造函数将 ICalc 直接注入 SalaryManager:
public class SalaryManager { private readonly ICalc _calc; public SalaryManager(ICalc clac) { _calc = calc; } public int DoCalculation(int a, int b) { int Sum = _calc.GetSum(a, b); //... } }
现在很容易将模拟的 ICalc 实例注入到您的 class, 只需使用 moq 创建 ICalc 的模拟并将其传递给 calss 通过构造函数。
如果您仍想使用工厂(这似乎 根据它的作用,在你的情况下非常无用,作为旁注,我倾向于在使用 DI 时使用工厂,只有当 class 依赖于一个我不想为 [= 保持活动状态的 IDisposable 对象时38=]的整个生命时间)就是要改变 它从静态方法到将实现一个具体工厂 接口:
public interface ISumFactory { ICalc GetCalc(int option); } public SumFactory : ISumFactory { public ICalc GetCalc(int option) { if (option == 1) return new NormalCalc(); return null; } }
现在你应该将工厂接口注入 SalaryManager class 通过它的构造函数并在需要时使用它:
public class SalaryManager { private readonly ICalcFacotry _calcFactory; public SalaryManager(ICalcFacotry clacFacotry) { _calcFactory = clacFacotry; } public int DoCalculation(int a, int b) { ICalc calc = _calcFactory.GetCalc(1); int Sum = calc.GetSum(a, b); //... } }
现在在你的单元测试中你可以创建 ICalcFacotry mock 并将其传递给你的 class,你应该将模拟的 facotry 设置为 return 当使用 facotry 方法时使用 1 作为 ICalc mock选项.
您可以在不更改源代码的情况下对该方法进行单元测试。
通过使用 Typmock Isolator,您将能够在 class 创建之前模拟它的未来实例,因此当您模拟 Iclac
的未来实例时,它将模拟所有 classes 实现了这个接口。
例如:
[TestMethod]
public void TestMethod()
{
//mock the future instances of Iclac
//and when the next NormalClac will be created it will be mocked as well
var fakeIclac = Isolate.Fake.NextInstance<ICalc>();
//setting the behavior of GetSum
Isolate.WhenCalled(() => fakeIclac.GetSum(0, 0)).WillReturn(5);
var result = new SalaryManager().DoCalculation(0, 0);
Assert.AreEqual(5, result);
}