我正在使用Moq库进行单元测试。现在我想要的是当我第一次访问我的对象时它应该返回null,当我第二次访问它时它应该返回其他东西。
这是我的代码
var mock = new Mock<IMyClass>();
mock.Setup(?????);
mock.Setup(?????);
var actual = target.Method(mock.object);
在我的方法中,我首先检查mock对象是否为null,如果为null,则进行初始化,然后对其进行一些调用。
bool Method(IMyClass myObj)
{
if (myObj != null)
return true;
else
{
myObj = new MyClass();
bool result = myObj.SomeFunctionReturningBool();
return result;
}
}
如何为模拟对象设置,
此外,我需要知道如何模拟这一行
bool result = myObj.SomeFunctionReturningBool();
答案 0 :(得分:2)
听起来你正试图用一种测试方法运行两个测试 - 也许最好将测试分成两个?
如果方法传递null,您还希望初始化一个新对象。为了测试这个,我建议创建一个负责创建MyClass
实例的工厂对象。新代码如下:
interface IMyClassFactory
{
IMyClass CreateMyClass();
}
bool Method(IMyClass myObj, IMyClassFactory myClassFactory)
{
if (myObj != null)
{
return true;
}
myObj = myClassFactory.CreateMyClass();
return myObj.SomeFunctionReturningBool();
}
然后测试看起来像:
[Test]
public void Method_ShouldReturnTrueIfNotPassedNull()
{
Assert.That(target.Method(new MyClass()), Is.True);
}
[Test]
public void Method_ShouldCreateObjectAndReturnResultOfSomeFunctionIfPassedNull()
{
// Arrange
bool expectedResult = false;
var mockMyClass = new Mock<IMyClass>();
mockMyClass.Setup(x => x.SomeFunctionReturningBool()).Returns(expectedResult);
var mockMyFactory = new Mock<IMyClassFactory>();
mockMyFactory.Setup(x => x.CreateMyClass()).Returns(mockMyClass.Object);
// Act
var result = target.Method(null, mockMyFactory.Object);
// Assert
mockMyClass.Verify(x => x.SomeFunctionReturningBool(), Times.Once());
mockMyFactory.Verify(x => x.CreateMyClass(), Times.Once());
Assert.That(result, Is.EqualTo(expectedResult));
}
此处factory pattern已用于传入可创建IMyClass
类型对象的对象,然后工厂本身已被模拟。
如果您不想更改方法的签名,则在类的构造函数中创建工厂,并通过类的公共属性访问它。然后它可以在模拟工厂的测试中被覆盖。这称为dependency injection。
答案 1 :(得分:0)
要模拟结果值,您可以执行以下操作:
mock.Setup(foo => foo.SomeFunctionReturningBool()).Returns(true); // or false :)
对于另一个问题,只需在单元测试中传递null,而不是传递mock.object
,你的单元测试也是如此。所以你基本上创建了两个单元测试:
var actual = target.Method(mock.object);
和另一个:
var actual = target.Method(null);
答案 2 :(得分:0)
您可以将TestFixture与参数一起使用。这个测试将运行两次和不同的类型值。
using NUnit.Framework;
namespace Project.Tests
{
[TestFixture(1)]
[TestFixture(2)]
public class MyTest
{
private int _intType;
public MyTest(int type)
{
_intType = type;
}
[SetUp]
public void Setup()
{
if (_intType==1)
{
//Mock Return false
}
else
{
//Mock Return Value
}
}
}
}
答案 3 :(得分:0)
目前,您的SUT与MyClass
实施紧密结合。您无法模拟在SUT中使用new
关键字实例化的对象。因此,您无法单独测试您的SUT,您的测试不再是单元测试 。当MyClass.SomeFunctionReturningBool
的实施发生变化时(它将返回true
而不是false
),您的SUT测试将失败。这不应该发生。因此,将创建委托给某个依赖项(工厂)并将该依赖项注入您的SUT:
[Test]
public void ShouldReturnTrueWhenMyClassIsNotNull()
{
Mock<IMyClassFactory> factory = new Mock<IMyClassFactory>();
Mock<IMyClass> myClass = new Mock<IMyClass>();
var foo = new Foo(factory.Object);
Assert.True(foo.Method(myClass.Object));
}
[Test]
public void ShouldCreateNewMyClassAndReturnSomeFunctionValue()
{
bool expected = true;
Mock<IMyClass> myClass = new Mock<IMyClass>();
myClass.Setup(mc => mc.SomeFunctionReturningBool()).Returns(expected);
Mock<IMyClassFactory> factory = new Mock<IMyClassFactory>();
factory.Setup(f => f.CreateMyClass()).Returns(myClass.Object);
var foo = new Foo(factory.Object);
Assert.That(foo.Method(null), Is.EqualTo(expected));
factory.VerifyAll();
myClass.VerifyAll();
}
BTW赋值方法参数的新值不会影响您传递给方法的引用。
实现:
public class Foo
{
private IMyClassFactory _factory;
public Foo(IMyClassFactory factory)
{
_factory = factory;
}
public bool Method(IMyClass myObj)
{
if (myObj != null)
return true;
return _factory.CreateMyClass().SomeFunctionReturningBool();
}
}
答案 4 :(得分:0)
Moq - 返回null - 这个工作示例简单地说明了如何使用Moq返回null。虽然需要的代码行是下面的注释行,但下面提供了一个完整的工作示例。
// _mockShopService.Setup(x => x.GetProduct(It.IsAny<string>())).Returns(() => null);
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
}
public interface IShopService
{
Product GetProduct(string productId);
}
public class ShopService : IShopService
{
public Product GetProduct(string productId)
{
if (string.IsNullOrWhiteSpace(productId))
{
return new Product();
}
return new Product { Id = "8160807887984", Name = "How to return null in Moq" };
}
}
public class Shop
{
private static IShopService _shopService;
public Shop(IShopService shopService)
{
_shopService = shopService;
}
public Product GetProduct(string productId)
{
Product product = _shopService.GetProduct(productId);
return product;
}
}
[TestClass]
public class ShopTests
{
Mock<IShopService> _mockShopService;
[TestInitialize]
public void Setup()
{
_mockShopService = new Mock<IShopService>();
}
[TestMethod]
public void ShopService_GetProduct_Returns_null()
{
//Arrange
Shop shop = new Shop(_mockShopService.Object);
//This is how we return null --- all other code above is to bring this line of code home
_mockShopService.Setup(x => x.GetProduct(It.IsAny<string>())).Returns(() => null);
//Act
var actual = shop.GetProduct(It.IsAny<string>());
//Assert
Assert.IsNull(actual);
}
}