[28] Learning C # interface Dependency Inversion, unit testing

What is the interface?

The nature of the interface: contract (contract) between the caller and the function of the provider functions common to follow

Why use an interface?

In the code, if the place can be replaced, there must exist an interface;Interface is to loosely coupled bornWhile the provider loosely coupled biggest advantage is to allow the function to become an alternative
Here Insert Picture Description
Here Insert Picture Description

Example 1: summing a set of integers, averaging operation

(This group may be an integer in an integer array, also be placed in the ArrayList)
(1) without using the interface: the need for separately summing the two types of write group of integers, the average of the static methods seek total write 4 method
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
(2) using the interface: As int [], ArrayList have achieved [this] IEnumerable interface may have to be iterative function, so long as the caller functions - sum, averaging method IEnumerable type of parameter type, it is not necessary to write the duplication of function approach
Here Insert Picture Description

Example 2: Start the car's engine needs

In other words: dependent on the car engine, forming a tightly coupled relationship between them
(1) do not use Interface: automotive and engine to form a tightly coupled relationship, but if _rpm field Engine class mistakenly written as 0, then even if Speed property Car instance is 0, or will print out the state "CAR iS running ..."
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
(2) using the interface for the purpose of loosely coupled (written it does not seem good)
Here Insert Picture Description

Example 3: The phone is broken how do

Contributors features: a variety of handsets; caller function: mobile phone users
(1) do not use interfaces, mobile phone users can only use one phone

(2) using the interface: not the old and new do not come - the entire latest Lord, God will!
Here Insert Picture Description
Here Insert Picture Description

Again: the interface is to loosely coupled born, it solves the tight coupling, a provider of irreplaceable function caused by high-risk, high-cost

Dependency Inversion Principle

High level modules should not depend upon low level modules,Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstracts.

高层模块不应该依赖低层模块,两者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象

依赖反转原则——面向接口编程,解耦在代码中的表现,其实就是依赖反转

例4:全能的司机

Here Insert Picture Description
(1)司机依赖于车:每个司机只能开一种车
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
(2)开始大乱斗:多个功能的提供者与多个功能的调用者都遵循同一个接口
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
(3)再加一个无人驾驶系统还不是小菜一碟?

  • 依赖反转原则,其实就是给我们提供了一种新的思维方式,用来【平衡】【自顶向下,逐步求精】这种单一的思维方式
  • 自顶向下,逐步求精:将大问题分解为小问题,小问题逐一解决后 ,大问题也就迎刃而解了;那么,解决问题的编程实体,就是函数,从而各个函数之间形成了【依赖关系】
    Here Insert Picture Description
  • 有了面向对象之后,函数都是封装在类和对象中的,所以依赖关系存在于类与类,对象与对象之间
  • 适当地引用接口,运用【依赖反转原则】,可以有效地减少耦合度,使代码更"清爽",更好维护

单元测试

单元测试其实就是依赖反转在开发当中的直接应用和直接受益者

什么是单元测试?

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

比如对函数abs(),我们可以编写出以下几个测试用例:

  1. 输入正数,比如1、1.2、0.99,期待返回值与输入相同;
  2. 输入负数,比如-1、-1.2、-0.99,期待返回值与输入相反;
  3. 输入0,期待返回0;
  4. 输入非数值类型,比如None、[]、{},期待抛出TypeError。

把上面的测试用例放到一个测试模块里,就是一个完整的单元测试。
如果单元测试通过,说明我们测试的这个函数能够正常工作。如果单元测试不通过,要么函数有bug,要么测试条件输入不正确,总之,需要修复使单元测试能够通过。

  • 单元测试通过后有什么意义呢?如果我们对abs()函数代码做了修改,只需要再跑一遍单元测试,如果通过,说明我们的修改不会对abs()函数原有的行为造成影响,如果测试不通过,说明我们的修改与原有行为不一致,要么修改代码,要么修改测试。

  • 这种以测试为驱动的开发模式最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。在将来修改的时候,可以极大程度地保证该模块行为仍然是正确的。

例5:不准乱碰电源

(1)风扇的运转是依赖于电源的
Here Insert Picture Description

(2)引入进口,进行解耦
接口的产生:自底向上(重构),自顶向下(设计)
自顶向下的情况一般是非常了解业务逻辑,一上来就知道该怎样设计代码,设计接口;但更多的情况是不断地重构代码,发现需要解耦,才返回来声明一个接口,如此下去
Here Insert Picture Description

(3)进行标准的单元测试

<1>打开 Test Explorer ,测试case和结果都会显示在其中
(Test ——Window)

<2>选择测试框架并命名
(右键 Solution ——Add ——new project ——Test),一般测试项目的命名都是被测试项目后加 “.Tests

  • 每一个类就是一组 Test case 【TestClass】
  • 每一个 Test case 就是一个方法 【TestMethod】

<3>在【InterfaceExample.cs】中引用被测试项目

<4> write test case
Here Insert Picture Description

<5> and then write the current situation other tests
assume a problem in the production of electric fans, when the voltage exceeds 200V, the warning not to, but directly explosion
Here Insert Picture Description
test:
Here Insert Picture Description

<6> Start debug
set breakpoints in the test case of the problem, right Failed Tests begin debug, you will find the problem in any place; the "! Explode" changed to "Warning!", By test

Note: The test code is also very important at work, do not ignore the test code

supplement

In Example 5, the first time I wrote code that there has been such a problem
Here Insert Picture Description
because:C # initialization variable precedence constructor
So the compiler can not guarantee when initializing variables I, can get the expected value

Published 29 original articles · won praise 3 · Views 919

Guess you like

Origin blog.csdn.net/weixin_44813932/article/details/104077547