【问题标题】:How to mock the class object which is created inside a method using new keyword in MOQ如何在 MOQ 中使用 new 关键字模拟在方法内创建的类对象
【发布时间】:2019-01-11 07:24:04
【问题描述】:

我正在使用 Moq 编写单元测试用例。

代码:

public class SavingAccount  
{  
    public void Data()  
    {  
        //Some logic
    }  
}  

public class Account  
{  
    public void GetAccountDetails()  
    {  
        SavingAccount savingAccount = new SavingAccount();  
        savingAccount.Data();  

        //Some logic
    }  
}

测试用例:

[TestClass]
public class AccountTest
{
    [TestMethod]
    public void TestGetAccountDetails()
    {
       using(var mock = new AutoMock.GetLoose())
       {
          var mockAccount = mock.Create<Account>();
          mockAccount.GetAccountDetails();
       }
    }
}

这里我需要模拟SavingAccount类的savingAccount.Data();方法。 但是当我运行上述测试时,savingAccount 对象实际上调用了Data() 方法。我不想叫它,只想嘲笑它。

我也不会更改上面的代码。我不想使用界面。

【问题讨论】:

  • 你在使用依赖注入吗?您可以更改原始文件以使用注入的工厂方法。
  • 没有约翰。我没有使用 DI。
  • 你必须去寻找一个可以模拟类初始化的模拟框架。然而,起订量没有这个功能,而且我知道没有免费的框架可以。
  • 当前显示的代码与实现问题紧密耦合,这使得单独测试主题代码变得困难。这应该被视为代码异味并相应地进行重构。

标签: c# moq rhino-mocks testcase


【解决方案1】:

我可以想到两种方法:

方法一。 创建一个工厂,并在实例化时将其传递给Account。当您需要 SavingAccount 时,请致电工厂:

    public class Account
    {
        private readonly IAccountFactory _accountFactory;

        public Account(IAccountFactory accountFactory)
        {
            _accountFactory = accountFactory;
        }

        public void GetAccountDetails()  
        {  
            SavingAccount savingAccount = _accountFactory.CreateSavingAccount();
            savingAccount.Data();  

            //Some logic
        }   
    }

然后您可以将IAccountFactory 的模拟实现传递给Account。这是我推荐的方式,如果您决定这样做,将来可以更轻松地过渡到依赖注入。

方法 2. 将 SavingAccount 的实例化移动到可模拟的方法中:

    public class Account  
    {  
        public void GetAccountDetails()  
        {  
            SavingAccount savingAccount = CreateSavingAccount();
            savingAccount.Data();  

            //Some logic
        }

        protected virtual SavingAccount CreateSavingAccount()
        {
            return new SavingAccount();
        }
    }

现在您可以模拟 CreateSavingAccount 并让它返回一个模拟的 SavingAccount 实例。请注意,您还需要将 public void Data() 更改为 public virtual void Data() 以便您可以模拟它。

【讨论】:

  • 谢谢约翰。我根本不想更改我的代码。对于您的解决方案,我需要更改我的代码。有没有其他办法。
  • 没有其他方法不涉及修改您的代码。
  • 好的。如果我遵循方法 2,那么我的测试用例会是什么样子。你能提供方法2的测试用例示例吗?
  • @John 让第二个解决方法发挥作用所需的努力值得吗?他们的代码与实现问题紧密耦合。虽然引入工厂方法将允许覆盖 SavingAccount 的创建,但您随后需要重构该类以允许成员被模拟框架模拟或手动创建派生类并在所述方法上新建以避免调用实际的实现。
【解决方案2】:

这是一个有点老的问题,但尽管如此。有现代的模拟框架可以模拟 new 操作符和新对象的创建,例如 JustMock。下面是一个模拟 SavingAccount 类的示例。

// Arrange the what SavingAccount should do 
var savingAccount = new SavingAccount();
Mock.Arrange(() => savingAccount.Data()).DoNothing();

// Arrange that every new creation of SavingAccount will return the object you've created above
Mock.Arrange(() => new SavingAccount()).Returns(savingAccount);

【讨论】:

    猜你喜欢
    • 2021-08-23
    • 1970-01-01
    • 2017-01-15
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多