测试懒人

I’ve recently looked through some current approaches to testing JavaScript applications and decided to summarize my thoughts in the form of an article. The huge part of this article is based on my reports that had been written more than a year ago. It is funny though, every single thing remains the same. Although frontend is one of the most dynamically evolving branches of software development, testing… testing never changes. It might seem like a huge understatement because every single week a new library is released but at the end of the day, we’re just operating around the same concepts and thoughts dressed in a different overlay. And this is awesome!

我最近浏览了一些测试JavaScript应用程序的最新方法,并决定以文章的形式总结我的想法。 本文的大部分内容基于我一年多以前写的报告。 有趣的是,每件事都保持不变。 尽管前端是软件开发中发展最快的分支之一,但是测试……测试永远不会改变。 这似乎是一种轻描淡写的说法,因为每个星期都会发布一个新的库,但是到了一天结束时,我们只是围绕着相同的概念和想法进行了覆盖。 这太棒了!

One of the greatest things I like about software development is this freedom of using some standardized patterns to focus our creativity in solving the edge-case problems. This way we can be lazy in a very fulfilled way.

我喜欢软件开发的最伟大的事情之一就是这种自由使用某些标准化模式来集中我们的创造力来解决极端情况的问题。 这样,我们可以以非常充实的方式懒惰。

So what does it actually mean? How to write tests when there are a lot of real problems to solve? How to use the Test-Driven Development approach when there is no time to prepare the same logic twice? In this paper, I’ll try to answer these questions. I can reveal a tip: it’s all about the wrong mindset that enforces us to think that our only goal as software engineers is to prepare a solution that solves problems. The truth is, our scope must be a lot wider.

那到底是什么意思呢? 当有很多实际问题需要解决时,如何编写测试? 当没有时间准备两次相同的逻辑时,如何使用测试驱动开发方法? 在本文中,我将尝试回答这些问题。 我可以揭示一个提示: 正是错误的思维方式使我们认为,作为软件工程师,我们唯一的目标是准备解决问题​​的解决方案 。 事实是,我们的范围必须更大。

I think, that most of the assumptions that you already have about testing are probably right. The problem is, even though many people know it, hardly anyone follows it appropriately. Testing shouldn’t be the thing you do to make your manager happy. It should make you confident about your job as a software engineer.

我认为,您已经对测试进行的大多数假设可能都是正确的。 问题是,即使许多人都知道它,却几乎没有人适当地遵循它。 测试不应该成为使经理高兴的事情。 它应该使您对作为软件工程师的工作充满信心。

Learning how to test your software can, at the same time, teach you how to be a better developer.

同时,学习如何测试软件可以教会您如何成为更好的开发人员。

This article won’t be framework-specific or even language-specific. I tried to give the most general examples as I could. It’s worth mentioning though, most of my assumptions are based on programming JavaScript-based projects (React, Angular, Node, etc.). In most cases, I tried to keep it as general as possible.

本文将不会针对特定框架,甚至不会针对特定语言。 我尽力给出最一般的例子。 不过,值得一提的是,我的大多数假设都是基于对基于JavaScript的项目进行编程( ReactAngularNode等)。 在大多数情况下,我试图使其尽可能通用。

Ah, yes, there is one more thing you need to know. All of the examples and approaches are presented from the perspective of a guy who spent all his dev career in tech startups. If that scares you then… it should. Ok, let’s dive into it.

啊,是的,您还需要了解一件事。 所有示例和方法都是从一个在技术初创公司中度过了全部开发生涯的家伙的角度呈现的。 如果那让您感到害怕,那应该。 好吧,让我们深入研究它。

效率 (Efficiency)

Image for post
Photo by Aron Visuals on Unsplash
Aron VisualsUnsplash上的 照片

What is the most time-efficient way of testing software? Release untested one and wait till users will tell us what we need to fix. That’s a statement that no developer should use (at least not loudly in the presence of the supervisors). In fact, this kind of thinking can lead to many problems a lot bigger than just crashing an app. There are two main stages that I’ll address in this section: before the release and after the release. They both have their own problems and consequences in case of badly thought out tests. Like I wrote at the beginning, it’s all about our confidence as the software developers but also you should remember that delivering a well-tested code is part of this job.

测试软件最省时的方法是什么? 释放未经测试的程序,然后等到用户告诉我们需要解决的问题。 那是一个声明,任何开发人员都不应使用(至少在主管的陪同下不要大声使用)。 实际上,这种想法可能导致许多问题,而不仅仅是崩溃一个应用程序。 本节将介绍两个主要阶段: 发布前和发布 。 万一测试考虑不周,它们都有自己的问题和后果。 就像我在开始时写的那样, 这完全取决于我们对软件开发人员的信心,但您还应该记住,交付经过良好测试的代码是这项工作的一部分

发布之前 (Before the release)

During the development process, there are a number of good practices and approaches that you should follow to gain a lot of time before the final release. Firstly, you must be confident that you understand the assumptions of this piece of software well. Testing is all about mimicking user behavior so if you don’t understand the way this function or component should be used you can’t test it properly. I would say that testing is more a human side of the development process and maybe that’s why it’s so hard for some of us. Okay, but apart of saving time, what this type of thinking can teach us? Well, it depends on our end-users. It’s worth mentioning at this point that they don’t have to be our clients, our piece of software can be used in other parts of the development pipeline. In general, it helps to broaden horizons and think about the way the other parts of the software pipeline works. In some cases, it might help to develop our UX skills, in other it helps to understand the complexities of communication with third-party services. Thinking about the way that users should use our block of code can be very developing.

在开发过程中,应遵循许多良好实践和方法,以便在最终版本发布之前花很多时间。 首先,您必须确信自己已经很好地理解了该软件的假设。 测试是关于模仿用户行为的所有内容,因此,如果您不了解应使用此功能或组件的方式,则无法正确测试。 我会说测试在开发过程中更像是人的一面,也许这就是为什么对于我们中的某些人来说如此困难。 好的,但是除了节省时间之外,这种思维方式还能教给我们什么? 好吧,这取决于我们的最终用户。 值得一提的是,他们不必成为我们的客户,我们的软件可以在开发管道的其他部分使用。 通常,它有助于拓宽视野并考虑软件管道的其他部分的工作方式。 在某些情况下,它可能有助于开发我们的UX技能,而在另一些情况下,它可以帮助您了解与第三方服务通信的复杂性。 关于用户应该使用我们的代码块的方式的思考可能正在发展。

Another, very important thing is to prepare solid codebase fundaments before you even start programming. In the case of web programming: are you using TypeScript, Linter, Prettier, Husky, or other useful tools? Is your Webpack configured properly? Do you use Docker or any other tools that can improve the integration of your app? Those are just a couple of examples. The concept of structure your project properly is completely another topic which I may cover in a separate article. Those types of practices can help you solve many simple problems that could potentially evolve into something more serious. Another really cool idea is to use functional programming principles. The less unpredictable side effects happen in our code the easier it is to test without the need to write a huge amount of mock logic.

另一个非常重要的事情是在开始编程之前就准备好扎实的代码基础 。 在Web编程的情况下:您使用的打字稿短绒更漂亮赫斯基 ,或其他有用的工具? 您的Webpack是否配置正确? 您是否使用Docker或任何其他可以改善应用程序集成的工具? 这些只是几个例子。 正确组织项目的概念完全是另一个主题,我可能会在另一篇文章中介绍。 这些类型的实践可以帮助您解决许多可能会演变为更严重问题的简单问题。 另一个很酷的想法是使用函数式编程原理。 在我们的代码中发生的不可预测的副作用越少,无需编写大量的模拟逻辑就可以更轻松地进行测试。

Next, we should think about what code we should test. In most cases, we shouldn’t really test our own code. The problem with this is when you try to test your own code you’re in many cases have too much trust in your own solution. Every time, when you test fails you think: oh, maybe it’s the test fault. Sometimes it is. But the thing is, to remain objective you shouldn’t know the details of the development process. You just have to focus on the output.

接下来,我们应该考虑应该测试什么代码。 在大多数情况下,我们不应该真正测试我们自己的代码。 问题在于,当您尝试测试自己的代码时,在很多情况下,您对自己的解决方案有太多的信任。 每当测试失败时,您都会想: 哦,也许是测试错误 。 有时候是。 但是, 要保持客观性,您不应该知道开发过程的细节 。 您只需要专注于输出即可。

发布后 (After the release)

The way you should think about a product in the production stage is how much self-sufficient your app can be. If your code breaks in production because of your omission the image of the company can suffer. It also may cost additional time to fix these issues. Another very important thing is to prepare a solid production environment to test and fix issues automatically without interrupting the lifecycle.

您应该在生产阶段考虑产品的方式是您的应用可以实现多少自给自足 。 如果您的代码因您的遗漏而中断了生产,那么公司的形象就会受到损害。 解决这些问题可能还会花费额外的时间。 另一个非常重要的事情是准备一个可靠的生产环境,以在不中断生命周期的情况下自动测试和修复问题。

三(半)测试Struts。 (Three (and a half) pillars of testing.)

Image for post
Frederic Köberl on FredericKöberl在Unsplash上的 Unsplash 照片

Typically you can list three base types of tests: unit, integration, and e2e. The idea behind this division is to differentiate the amount of time needed to prepare tests but also to estimate the level of confidence given by a particular test.

通常,您可以列出三种基本测试类型:单元测试,集成测试和e2e。 这种划分的思想是区分准备测试所需的时间,同时也要估计特定测试给出的置信度。

单元测试 (Unit tests)

They are considered as the most basic type of tests. They are based on the conception of testing the smallest units in order to examine the correctness of their work. Those units could be function, components, or functional parts of the components (lists, forms, etc.). The main goal is to compare the result value with the planned one using the helper tools. The basic principle of unit tests is their purity. You must ensure that the variables modified in one test do not affect the other. Every unit test should be seen as a unique, distinct instance (black box). In reality, though, most of the unit tests can’t be executed without the context. Unit tests as the smallest ones, mostly are executed in a group so we must create separate environments for different use cases.

它们被认为是最基本的测试类型。 它们基于测试最小单元以检查其工作正确性的概念。 这些单元可以是功能,组件或组件的功能部分(列表,表单等)。 主要目标是使用助手工具将结果值与计划的结果进行比较。 单元测试的基本原理是其纯度。 您必须确保在一个测试中修改的变量不会影响其他测试。 每个单元测试都应被视为唯一的,不同的实例(黑盒)。 但是,实际上,大多数单元测试都离不开上下文。 单元测试是最小的测试,大多数都是在一个组中执行的,因此我们必须为不同的用例创建单独的环境。

Level of complexity: 🟢 🟢 🟢

复杂程度:

Level of confidence: 🔴

置信度:🔴

整合测试 (Integration tests)

In this case, we check how individual units (functions, components) work together to create a complete system. Usually, unit tests are seen as the “checkpoints” in the path that the program goes through testing the units in the correct order. These units are executed within the same context, sharing the global data. As you can see, this is a kind of simulation of real user behavior. At least they are more reliable in this respect than unit tests. The boundary between unit and integration tests is often blurred (unit tests of a complex component may be very similar to integration tests and vice versa). Paths are typically divided into happy and sad. Happy paths occur when the program executes instructions as expected by the system (no validation errors, illegal operations, etc.). We check how the system works in the most common cases. Sad paths are non-obvious ones, during which some errors may occur. We check in this case how well the system handles such edge-situations. These tests should be used as often as possible because they allow determining the measurable value of our security and data flow (as opposed to unit tests, they test the entire sequence).

在这种情况下,我们检查各个单元(功能,组件)如何协同工作以创建一个完整的系统。 通常,单元测试被视为程序以正确顺序进行单元测试的“检查点”。 这些单元在相同的上下文中执行,共享全局数据。 如您所见,这是对真实用户行为的一种模拟。 至少在这方面,它们比单元测试更可靠。 单元测试和集成测试之间的界限通常是模糊的(复杂组件的单元测试可能与集成测试非常相似,反之亦然)。 路径通常分为快乐和悲伤。 当程序按照系统预期执行指令时,将出现快乐路径(无验证错误,非法操作等)。 在最常见的情况下,我们会检查系统的工作方式。 悲伤的路径是非显而易见的路径,在此期间可能会发生一些错误。 在这种情况下,我们将检查系统处理此类边缘情况的能力。 这些测试应尽可能频繁地使用,因为它们可以确定我们的安全性和数据流的可测量值(与单元测试相反,它们可以测试整个序列)。

Level of complexity: 🟡 🟡

复杂程度:

Level of confidence: 🟡 🟡

置信度:🟡

端到端测试 (E2e tests)

They are most commonly used to cover some particular, most important from the business perspective areas. Because of their large complexity, they are not that widely used as integration or unit tests.

从业务角度来看,它们最常用于覆盖某些特定的,最重要的区域。 由于它们的复杂性很大,因此没有广泛用作集成或单元测试。

Level of complexity: 🔴

复杂程度:🔴

Level of confidence: 🟢 🟢 🟢

置信度:

其他工具 (Additional tools)

The code coverage is one of the determinants of the quality of the tests. It shows what percentage of our code is covered by tests. This is a very useful tool, but cannot be overestimated. Tests should be written primarily with a focus on covering all edge cases. The approach to achieve 100% code coverage can seriously extend the development process. Wanting to get a result above a certain level often involves modifying the source code to pass the tests, and this is obviously pointless. Ultimately, of course, everything depends on the specific case, the analysis of the appropriateness of a given coverage threshold should be carried out before the start of the development process. Tests should be thought out then implemented in order proportional to their level of significance.

代码覆盖率是测试质量的决定因素之一。 它显示了测试覆盖了我们代码的百分比。 这是一个非常有用的工具,但不能高估。 测试应主要写在涵盖所有边缘情况的地方。 实现100%代码覆盖率的方法可以严重扩展开发过程。 想要获得高于特定水平的结果通常涉及修改源代码以通过测试,这显然是没有意义的。 最终,当然,一切都取决于具体情况,应该在开发过程开始之前对给定覆盖率阈值的适当性进行分析。 应该考虑测试,然后按照重要性程度按比例进行测试。

测试驱动开发 (Test-Driven Development)

One of the most popular ways of writing tests in software development is TDD. This approach assumes the division of functionality into small pieces that can be easily tested and can be assembled into one working logic. The big advantage is that in the end, we have the solution with complex, multistep tests. In theory, it seems to be a perfect solution.

TDD是软件开发中编写测试的最流行方法之一。 这种方法假定将功能划分为小块,可以轻松测试这些小块并将其组装为一个工作逻辑。 最大的优势在于,最终,我们有了包含复杂,多步骤测试的解决方案。 从理论上讲,这似乎是一个完美的解决方案。

In some cases it is, it gives us a sufficient amount of confidence. It happens especially often when we’re working on a solution that is predictable in every step of implementation. For example, when it’s built with the functional programming patterns. When you think about it, the pure functions are in general very easy to test so it seems like a perfect fit. Another cool thing is, the TDD approach teaches us discipline and organizes our workflow.

在某些情况下,它为我们提供了足够的信心。 当我们正在研究可在实施的每个步骤中预测的解决方案时,这种情况尤其经常发生。 例如,当使用功能性编程模式构建时。 考虑一下时,纯函数通常很容易测试,因此看起来很合适。 另一个很酷的事情是,TDD方法教我们纪律并组织工作流程。

When you’re implementing an experimental solution that isn’t that easy to predict or to split into simple pieces you’d probably have to work on the overall architecture. Another reason why I don’t use TDD that much in my work is that it assumes that you should write tests for your own code. Like I’ve written in the previous section, I’m not a huge fan of this procedure.

当您实施一个不容易预测或分解成简单部分的实验性解决方案时,您可能必须在整个体系结构上工作。 我在工作中不使用TDD的另一个原因是,它假定您应该为自己的代码编写测试。 就像我在上一节中所写的那样,我不是这个过程的忠实拥护者。

Don’t get me wrong, it’s a really powerful approach but if you have to force yourself to keep every single assumption of the Test-Driven Development it doesn’t make much sense. Tools that we’re using should increase our productivity and creativity.

别误会我的意思,这是一种非常有效的方法,但是如果您不得不强迫自己坚持测试驱动开发的每个假设,那么这没有多大意义。 我们正在使用的工具将提高我们的生产力和创造力。

结论 (Conclusions)

There are many nuances that can make us focus on completely irrelevant elements. Thinking whether a particular test is a unit test or integration test, focusing on achieving a specific code coverage level, etc. We’re testing to feel better. To feel more confident about our work. To make sure that the program we write will not crash on production and end-users will be, eventually, satisfied. The software should be tested exactly the same way as it will be used. Therefore, do not worry too much about the implementation details. During tests operate on elements and search for them exactly as if the user was doing it.

有许多细微差别可以使我们专注于完全不相关的元素。 考虑特定的测试是单元测试还是集成测试,重点在于达到特定的代码覆盖级别等。我们正在测试以使其感觉更好。 对我们的工作更有信心。 为确保我们编写的程序不会在生产时崩溃,最终用户将满意。 应该使用与软件完全相同的方式对其进行测试。 因此,不必太担心实现细节。 在测试期间,将对元素进行操作,并完全像用户在进行操作一样搜索它们。

翻译自: https://medium.com/pluscode/testing-for-lazy-people-5f915dbc24ac

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值