首页 > 解决方案 > 从抽象类继承并实现接口的模拟类

问题描述

假设以下场景:我有一个PhoneController使用类的Phone类。Phone是一个继承自抽象类Device并实现IPhone接口的类。为了测试PhoneController我想模拟Phone类,但我不知道如何使用 NSubstitute 来完成,因为Phone类继承了抽象类,另外它实现了接口。

示例代码:

public abstract class Device
{
    protected string Address { get; set; }
}

public interface IPhone
{
    void MakeCall();
}

public class Phone : Device, IPhone
{
    public void MakeCall()
    {
        throw new NotImplementedException();
    }
}

public class PhoneController
{
    private Phone _phone;

    public PhoneController(Phone phone)
    {
        _phone = phone;
    }
}

[TestClass]
public class PhoneControllerTests
{
    [TestMethod]
    public void TestMethod1()
    {
        // How mock Phone class? 
        //var mock = Substitute.For<Device, IPhone>();

        //usage of mock
        //var controller = new PhoneController(mock);
    }
}

第二种情况:

控制器使用抽象类中的GetStatus方法,因此不能更改为类型Device_phoneIPhone

public abstract class Device
{
    protected string Address { get; set; }

    public abstract string GetStatus();
}

public interface IPhone
{
    void MakeCall();
}

public class Phone : Device, IPhone
{
    public void MakeCall()
    {
        throw new NotImplementedException();
    }

    public override string GetStatus()
    {
        throw new NotImplementedException();
    }
}

public class PhoneController
{
    private Phone _phone;

    public PhoneController(Phone phone)
    {
        _phone = phone;
    }

    public string GetDeviceStatus()
    {
        return _phone.GetStatus();
    }

    public void MakeCall()
    {
        _phone.MakeCall();
    }
}

[TestClass]
public class PhoneControllerTests
{
    [TestMethod]
    public void TestMethod1()
    {
        // How mock Phone class? 
        //var mock = Substitute.For<Device, IPhone>();

        //usage of mock
        //var controller = new PhoneController(mock);
    }
}

标签: c#unit-testingmockingnsubstitute

解决方案


有几种方法可以做到这一点,您选择哪一种取决于您要测试的内容。

  1. 您可以模拟 iPhone 界面(正如您在注释掉的代码中所做的那样。

  2. 您可以子类化电话类(手动或使用 NSubstitute 的.ForPartsOf<>)。有关此的博客文章,请参见此处

我发现如果我使用 Arrange/Act/Assert 方法构建我的测试,那么我要测试的内容会更清楚(理想情况下,您的 Act 部分应该有一个调用;例如:

[TestMethod]
public void TestMethod1()
{
    // Arrange
    var mock = Substitute.For<IPhone>();
    var controller = new PhoneController(mock);

    // Act
    int result = controller.Method();

    // Assert
    Assert.Equal(result, 3);
}

编辑 - 基于更新的评论

您不能对抽象类进行单元测试,因为该类不包含(根据定义)任何代码。在您的场景中,看起来您正在尝试做的是测试具体Phone类。如果是这种情况,那么只需创建Phone该类的一个实例并对其进行测试;您不需要涉及控制器:

// Arrange
var phone = new Phone();

// Act
string result = phone.GetStatus();

// Assert
Assert.Equal("New", result);

推荐阅读