|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- # 为什么测试这么重要
-
- `人非圣贤孰能无过`,归根结底,代码是人写的,`Bug`终究是无法避免的。测试的目的是为了尽早发现问题,尽量减少`Bug`数量。
-
- # 测试类型
-
- ## `Smoke test`
-
- - 程序员自己测试
-
- ## `Unit Tests`
-
- - 通常由程序员做
- - 快,几毫秒
- - 独立
- - 一次测试一种行为
- - 不依赖于外界,比如使用`Moq`和`nSubstitute`
-
- ## `Integration Tests`
-
- - 通常由程序员做
- - 相对较慢
- - 依赖于外部实现,比如依赖数据库、外部服务
-
- ## `Functional Tests`
-
- - 从用户的角度测试功能,可能是内测人员
- - 可以手动测试,也有自动测试框架
-
- ## `Subcutaneous Tests`
-
- - 最接近`UI`下的测试
- - 通常由程序员做
- - 适合逻辑在后端业务层,比如前后端分离的后端业务层
-
- ## `Load Tests`
-
- - 通常由程序员做
- - 模拟程序的负载
- - 通常查看各项性能指标
-
- `Stress Tests`
-
- - 通常由程序员做
- - 通常查看`CPU`,`Network`,`Memory`指标
-
- ![t3](F:\SourceCodes\DDWiki\专题\后端\测试\t3.png)
-
- # 单元测试的要和不要
-
- 要
-
- - 要间接测试私有方法
- - 要符合条件/不符合条件的输入
- - 容易出问题的代码要单元测试,比如包含正则表达式
- - 很难被捕捉的异常要单元测试,比如路由、算法
-
- 不要
-
- - 不要100%的覆盖率,没太必要
- - 不要给依赖组件的运行时错误进行单元测试
- - 不要在数据库架构、外部服务方面进行单元测试
- - 性能测试不通过单元测试
- - 代码生成器生成的代码不需要单元测试
- - 如果测试代码远大于被测试代码不需要单元测试
-
- # 一定要让测试不通过
-
- 不好的
-
- ```
- [Test]
- public void ShouldAddTwoNumbers()
- {
- var calculator = new Calculator();
- var result = calculator.Sum(10, 11);
- Assert.Equal(21, result);
- }
-
- // The method to test in class Calculator ...
- public int Sum(int x, int y)
- {
- throw new NotImplementedException();
- }
- ```
-
-
-
- 好的
-
- ```
- [Test]
- public void ShouldAddTwoNumbers()
- {
- var calculator = new Calculator();
- var result = calculator.Sum(10, 11);
- Assert.Equal(21, result);
- }
-
- // The method to test in class Calculator ...
- public int Sum(int x, int y)
- {
- return 0;//返回一个值让不通过
- }
- ```
-
- # 通过单元测试消除`Bug`
-
- 如果通过单元测试发现一个`Bug`, 即单元测试显示红灯。重构代买,单元测试通过,显示绿色。于是,单元测试起到了帮助代码重构的作用。
-
-
-
- # 流行的测试框架
-
- - `NUnit`: 是`.NET`开源的、被认可的测试框架,有`UI`
- - `XUnit`: 来之`NUnit`作者,最新的,鼓励`TDD`的开发方式,甚至`.NET Core`团队也在使用
- - `MSTest`: 微软的测试框架,无法在`build server`跑`CI/CD`
-
- # 持续集成服务器
-
- 监控源代码,一旦有变化,检查、构建、自动测试、发送报告等。
-
- # 测试项目的文件结构
-
- ![t4](F:\SourceCodes\DDWiki\专题\后端\测试\t4.png)
-
- # 命名
-
- - `MethodName_StateUnderTest_ExpectedBehavior`
-
- ```
- isAdult_AgeLessThan18_False
- withdrawMoney_InvalidAccount_ExceptionThrown
- admitStudent_MissingMandatoryFields_FailToAdmit
- ```
-
- - `MethodName_ExpectedBehavior_StateUnderTest`
- - `test[Feature being tested]`
-
- ```
- testIsNotAnAdultIfAgeLessThan18
- testFailToWithdrawMoneyIfAccountIsInvalid
- ```
-
- - `Feature to be tested`
-
- ```
- IsNotAnAdultIfAgeLessThan18
- FailToWithdrawMoneyIfAccountIsInvalid
- ```
-
- - `Should_ExpectedBehaviour_When_StateUnderTest`
-
- ```
- Should_ThrowException_When_AgeLessThan18
- Should_FailToWithdrawMoney_ForInvalidAccount
- ```
-
- - `When_StateUnderTest_Expect_ExpectedBehavior`
-
- ```
- When_AgeLessThan18_Expect_isAdultAsFalse
- When_InvalidAccount_Expect_WithdrawMoneyToFail
- ```
-
- - `Given_Preconditions_When_StateUnderTest_Then_ExpectedBehavior`
-
- ```
- Given_UserIsAuthenticated_When_InvalidAccountNumberIsUsedToWithdrawMoney_Then_TransactionsWillFail
- ```
-
- # `AAA`
-
- ```
- [TestMethod]
- public void TestRegisterPost_ValidUser_ReturnsRedirect()
- {
- // Arrange
- AccountController controller = GetAccountController();
- RegisterModel model = new RegisterModel()
- {
- UserName = "someUser",
- Email = "goodEmail",
- Password = "goodPassword",
- ConfirmPassword = "goodPassword"
- };
- // Act
- ActionResult result = controller.Register(model);
- // Assert
- RedirectToRouteResult redirectResult = (RedirectToRouteResult)result;
- Assert.AreEqual("Home", redirectResult.RouteValues["controller"]);
- Assert.AreEqual("Index", redirectResult.RouteValues["action"]);
- }
- ```
-
- # 数据量很大很难测试时用单元测试
-
- 被测代码,数量越大越难测,很有必要使用单元测试。
-
- ```
- public decimal CalculateTotal(List<myitem> items)
- {
- decimal total = 0.0m;
- foreach(MyItem i in items)
- {
- total += i.UnitPrice * (i - i.Discount);
- }
- return total;
- }
- ```
-
- # 保持被测方法不要过于复杂
-
- # `Test Explorer`的使用
-
- ![t5](F:\SourceCodes\DDWiki\专题\后端\测试\t5.png)
-
- ![t6](F:\SourceCodes\DDWiki\专题\后端\测试\t6.png)
-
-
-
- # 对被测代码复杂逻辑的封装
-
- 不好
-
- ```
- while ((ActiveThreads > 0 || AssociationsQueued > 0) && (IsRegistered || report.TotalTargets <= 1000 )
- && (maxNumPagesToScan == -1 || report.TotalTargets < maxNumPagesToScan) && (!CancelScan))
- ```
-
- 好的
-
- ```
- while (!HasFinishedInitializing (ActiveThreads, AssociationsQueued, IsRegistered,
- report.TotalTargets, maxNumPagesToScan, CancelScan))
- ```
-
- # 使用`Selenium`进行`Web`测试
-
|