依赖反转与单元测试(xunit)

前言

单元测试其实就是依赖反转的一个具体的实现案例。

依赖反转

首先让我们以电扇生产为例子进行演示,因为电扇依赖于电源,所以我们先定义一个电源类:

    public class PowerSupply
    {
        private int _power;

        public int GetPower()
        {
            return 100;
        }
    }

接下来就可以生产电扇了,借助定义一个电扇类:

    public class DeskFan
    {
        private PowerSupply _powerSupply;
        public DeskFan(PowerSupply powerSupply)
        {
            _powerSupply = powerSupply;
        }

        public string Work()
        {
            int power = _powerSupply.GetPower();
            if(power < 0)
            {
                return "Won't work";
            }
            else if(power < 100)
            {
                return "Slow";
            }
            else if(power < 200)
            {
                return "Work fine";
            }
            else
            {
                return "Warning!";
            }
        }
    }

现在有一个问题,那就是电扇类和电源类是紧耦合的,我们想要测试DeskFan实例的Work方法则需要修改电源类的GetPower方法的返回值,这违背了面向对象设计原则中的开闭原则,不是为了修复bug或者增加新功能的情况下不应该去修改已经定义好的类。这个时候可以通过接口来实现依赖反转。我们可以定义一个IPowerSupply的接口:

    public interface IPowerSupply
    {
        int GetPower();
    }

然后让电源实现这个接口中的方法:

    public class PowerSupply:IPowerSupply
    {
        public int GetPower()
        {
            return 100;
        }
    }

此时电扇类中_powerSupply字段类型修改为IPowerSupply类型:

    public class DeskFan
    {
        private IPowerSupply _powerSupply;
        public DeskFan(IPowerSupply powerSupply)
        {
            _powerSupply = powerSupply;
        }

        public string Work()
        {
            int power = _powerSupply.GetPower();
            if(power < 0)
            {
                return "Won't work";
            }
            else if(power < 100)
            {
                return "Slow";
            }
            else if(power < 200)
            {
                return "Work fine";
            }
            else
            {
                return "Warning!";
            }
        }
    }

于是乎我们就可以使用测试电源来测试电扇的工作状态了吗,先定义一个测试电源类:

    public class TestPowerSupply:IPowerSupply
    {
        public int GetPower()
        {
            return 300;
        }
    }

然后测试电扇的输出:

            TestPowerSupply testPowerSupply = new TestPowerSupply();
            DeskFan deskFan = new DeskFan(testPowerSupply);
            Console.WriteLine(deskFan.Work()); // Output: Warning
            Console.ReadKey();


这就将原来自顶向下的依赖关系(电扇依赖于某一个具体的电源):
在这里插入图片描述

转变为电扇依赖于电源,但并非某一具体的电源,可以是厂家自产的电源,也可以是用于测试的电源(原来向下的箭头向上了,这便是依赖反转的由来):
在这里插入图片描述

单元测试

一般情况下,TestPowerSupply不应该写在源代码中,而是应该新建一个测试项目用来测试电扇的工作情况。我们新建一个xunit的单元测试(在Visual studio中搜索xunit即可创建,创建完成以后要引用一下你要测试的项目)。
此处我们用命令行的方法新建一个xunit,在你的项目目录旁边打开PowerShell(按住shift键右击空白处选择PowerShell):

mkdir ConsoleApp.Tests
cd ConsoleApp.Tests
dotnet new xunit --framework netcoreapp3.1
dotnet add reference ..\ConsoleApp\ConsoleApp.csproj
dotnet restore
dotnet build

在这里插入图片描述

看一下输出结果:

在这里插入图片描述
在这里插入图片描述


用你习惯的IDE打开项目,然后编写如下代码进行测试:

using System;
using Xunit;

namespace ConsoleApp.Tests
{
    public class DeskFanTests
    {
        [Fact]
        public void PowerHigherThan200_Warning()
        {
            TestPowerSupply testPowerSupply = new TestPowerSupply();
            DeskFan fan = new DeskFan(testPowerSupply);
            var expected = "Warning!";
            var actual = fan.Work();
            Assert.Equal(expected,actual);
        }
    }

    public class TestPowerSupply: IPowerSupply
    {
        public int GetPower()
        {
            return 201;
        }
    }

}

在PowerShell中输入dotnet test,显示通过:
在这里插入图片描述
不过这样还是有一个弊端,那就是每次测试的时候都要写一个测试类,会比较麻烦,于是可以使用第三方库Moq来测试,在Nuget中添加Moq,或者在命令行中继续输入 dotnet add package 添加Moq包
在这里插入图片描述



使用Moq可以少些很多代码:

using System;
using Xunit;
using Moq;

namespace ConsoleApp.Tests
{
    public class DeskFanTests
    {
        [Fact]
        public void PowerHigherThan200_Warning()
        {
            var mock = new Mock<IPowerSupply>();
            mock.Setup(ps => ps.GetPower()).Returns(() => 201);
            DeskFan fan = new DeskFan(mock.Object);
            var expected = "Warning!";
            var actual = fan.Work();
            Assert.Equal(expected, actual);
        }
    }
}

参考文献

  1. C#语言入门详解(029)

及时获取我发的文章,学习更多编程知识欢迎关注我的个人微信公众号:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值