我应该在AngularJS中测试什么?

时间:2014-02-21 12:36:31

标签: angularjs unit-testing testing karma-runner

如今,特别是在angularjs测试领域,有很多指南可用于进行不同类型的测试,如单元测试,中途测试和端到端测试,在这里您可以学习如何对控制器,工厂进行不同的测试等等。

主题是,什么应该是可测试的?我可以测试我的模块应用程序有控制器,指令,成功登录,检查后端调用等。但我应该测试什么?,因为你可以测试所有的东西,可能它不是一个很好的做法“轻松测试”。

有人可以给我任何建议吗?谢谢。

2 个答案:

答案 0 :(得分:6)

对于一般性答案,您可以查看此question

假设您对角度的单元测试是用Jasmine或类似的方式编写的,请注意Jasmine适用于“行为驱动开发”。

来自this presentation: “行为驱动 - 开发是关于通过从利益相关者的角度描述其行为来实现应用程序”

另一个好的来源,但更严格(面向TDD或测试驱动开发)是Bob Martin的清洁代码。我最大的测试要点:

  • 让测试成为您的文档
  • 您的测试让您无需重构
  • 靠近用户或消费者进行测试,并在需要时向内工作

也就是说,

  • 评论可能会过时,但单元测试必须响应变化才能通过。如果您按照BDD建议编写特定用户场景,这尤其重要。
  • 如果您将测试视为需求摘要,只要您为新功能进行代码更改并运行测试套件,您就会立即知道您的代码是否仍符合要求。
  • 私有帮助程序方法,返回类型和数据结构可能经常更改。用户或消费者并不关心这些,只是对于给定的一组输入,他们会得到一定的效果或回报。

的示例:

作为一个粗略的例子,假设您需要一个应用程序来轮询给定城市的天气预报数据。您的用户或客户代码的要求可能类似于“给定一组天气数据,当我输入城市名称时,我应该获得5天的预测数据”。然后,您可能会进行如下测试:

  describe('Given a set of weather data'....
      ...
      describe('when I enter Los Angeles', function() {
          it('should return 5 days of forecast data for Los Angeles', 
          mocks.inject(function(weatherService) {
          var result = weatherService.getForecast('Los Angeles');
            expect(result.DayToForecast.lenth).toEqual(5);
          }));
      });
      ...

然后假设您有另一个要求,即天气数据会说出有关湿度的信息,例如“给定一组天气数据,当我输入城市名称和日期时,我应该获得湿度数据”

      ...
      describe('When I enter Los Angeles and Monday', function() {
          it('should return humidity data for Los Angeles on Monday', 
          mocks.inject(function(weatherService) {
          var result = weatherService.getForecast('Los Angeles');
            expect(result.DayToForecast['Monday'].humidity).not.toBe(null);
          }));
      });
      ...

这里我们并不关心结果的结构,只是它在某种程度上给出了星期一湿度的概念。我们并不关心weatherService的内部(例如,它是否从数据库,静态文件或其他Web服务获取数据)。你可能会有类似的东西,但仍然表达了要求:

      ...
      describe('when I enter Los Angeles and Monday', function() {
          it('should return humidity data for Los Angeles on Monday', 
          mocks.inject(function(weatherService) {
          var result = weatherService.getForecast('Los Angeles','Monday');
            expect(result.humidity).not.toBe(null);
          }));
      });
      ...

这里很酷的是你可以'通过一厢情愿的思考' - 你创建靠近你的用户和用例的功能签名,然后填写它们,只获得你需要的东西。现在,如果您的第一个要求改变为“给定一组天气数据,当我输入城市名称时,我应该获得4天的预测数据”,您必须更改测试而不是搜索评论,而您只需要更改与该需求变更相关的代码。

您的某些行为可能未被您的用户明确说明。例如,对于上面的示例,最终用户不太可能比Web服务消费者客户端说:“给定一组天气数据,当我输入城市名称和虚构的一天时,我应该得到一个例外“你必须自己收集这个和测试用例:

      ...
      describe('when I enter Los Angeles and EigthDay', function() {
          it('should throw an exception', 
          mocks.inject(function(weatherService) {
          var weatherServiceCall = function(){
                weatherService.getForecast('Los Angeles','EighthDay');
              };
              expect(weatherServiceCall).toThrow();
          }));
      });
      ...

答案 1 :(得分:1)

理想情况下,你应该测试一切。

我通常会尝试在编码前编写单元测试。这是为了确保我写的代码满足一些最小规范 - 它给出了我想要的输出。您的单元测试也应该作为一种预集成测试在其他部分中运行 - 我是否在进行此更改时在代码的另一部分中破坏了某些内容?通过这种方式,单元测试为程序提供了第一个网关。

请注意,在编写单元测试时,它们对用户体验的内容意义不大。也许该网站在单元测试的理论范围内功能正常,但在某些条件下,它们可能会极大地影响用户的体验?也许您添加的功能之一会降低页面加载速度?或以某种无法预料的方式打破用户界面。你的单元测试可能不会对此有所了解。

Moo年对这里不同类型的angularjs进行了很好的概述 - http://www.yearofmoo.com/2013/01/full-spectrum-testing-with-angularjs-and-karma.html

您还应该阅读持续集成测试 - 这将让您了解大型项目如何测试和集成代码,以确保它符合质量指南并且不会破坏现有代码。在大型项目中,几乎所有东西都应该有相应的单元测试。

将测试视为管道

  • 是否适用于初始设计?
  • 是否会破坏其他任何代码?
  • 它是否适用于更广泛的应用程序环境?
  • 是否会影响用户体验?

现在,如果您正在尝试优先考虑测试内容 - 测试您认为单元测试过于复杂的任何内容,并尝试编写尽可能多的E2E测试场景。如果你发现你的E2E测试失败很多,那就暗示你需要更多的单元测试,因为你发现了很多你可能不知道的边缘情况/未定义的行为。

您绝对应该为控制器和指令编写单元测试,因为它们构成了应用程序的狮子会共享,并且通常定义您的业务逻辑。