admin管理员组

文章数量:1529447

软件测试速成

As software engineers, we want to write code that not only works, but works in every possible situation a user could find themselves in. Under any circumstance, we want our code to run the way we designed it to run, or at the very least communicate clearly what went wrong.

作为软件工程师,我们希望编写的代码不仅可以工作,而且可以在用户可能遇到的每种情况下工作。在任何情况下,我们都希望代码按照设计时的方式运行,或者至少清楚地沟通出了什么问题。

Enter testing.

输入测试

Testing is the way we test our programs. Simple. The concept alone may be intuitive, but there’s a bit more nuance to how we design tests effectively and efficiently.

测试是我们测试程序的方式。 简单。 单独的概念可能很直观,但是我们如何有效地设计测试还有更多细微差别。

The great conflict of testing is that

测试的最大矛盾是

  1. Everyone wants their code to work.

    每个人都希望他们的代码能够正常工作。
  2. No one wants to write tests to ensure their code works.

    没有人愿意编写测试来确保其代码正常工作。

To wiggle their way out of this dilemma, software engineers devised methods so that they could rigorously derive as much confidence in their programs as possible whilst consuming the least amount of energy.

为了摆脱困境,软件工程师设计了一些方法,以便他们可以在消耗最少能量的情况下,尽可能严格地对自己的程序产生信心。

The way I think of it, we have a spectrum of tests starting with the most effort and the most confidence in our code working, to very little effort and less confidence in our testing. We want to make tests intelligently so we can fall above the line, so we are getting enough confidence in our program with the least amount of effort.

按照我的想法,我们进行了一系列测试,从对代码工作的最大努力和最大信心开始,到对我们的测试的很少努力和信心不足。 我们希望智能地进行测试,以使我们能够脱颖而出,因此我们用最少的精力就可以对程序充满信心。

Before software engineers got to systematic testing, I imagine they went through something similar to the following intuition:

在软件工程师进行系统测试之前,我想他们经历了类似于以下直觉的事情:

“Let’s just run our program and see if it works.” This is known as haphazard testing. When things started getting rough because they were ensuring little to no accuracy in their programs, they thought of something else.

“让我们运行我们的程序,看看它是否有效。” 这就是所谓的偶然性测试。 当由于无法确保程序的准确性而使事情开始变得艰难时,他们想到了其他事情。

“What if we tested everything?” This is called exhaustive testing. I made sure to say “what if” at the beginning because even if we were to just test a simple addition function exhaustively…

“如果我们测试了所有东西怎么办?” 这称为详尽测试。 我一定要在开始时说“如果”,因为即使我们只是穷举测试简单的加法功能……

def add(a, b):
return a + b

We would have to test for 2⁶⁴ cases because there are a lot of integers. That’s just for a simple addition function, so you can imagine why they wouldn’t want to continue with this approach.

因为有很多整数,所以我们将必须测试2个案例。 那只是一个简单的加法函数,因此您可以想象为什么他们不想继续使用这种方法。

Sometime after this, they worked through many different approaches, one of which was random testing. This was an attempt to automate test creation by testing cases randomly and hopefully covering all the important bases. Of course, as you can tell, this was not sustainable, because many important cases, including boundary cases which I’ll talk more about later, can easily be skipped over when testing randomly. This is not to mention just the sheer lack of confidence that comes from not writing the tests yourself.

此后的某个时候,他们采用了许多不同的方法,其中一种是随机测试。 这是通过随机测试用例并希望涵盖所有重要基础来自动化测试创建的尝试。 当然,正如您所知道的那样,这是不可持续的,因为在随机测试时,很容易跳过很多重要的案例,包括稍后将要讨论的边界案例。 这不仅是因为您自己不编写测试而导致的完全缺乏信心。

系统测试 (Systematic testing)

So eventually we arrived at systematic testing. With systematic testing, we write the tests ourselves, but we design them with intention so that they meet a set of three criteria. We want our test suite to be

所以最终我们到达了系统测试。 通过系统的测试,我们可以自己编写测试,但是我们有针对性地设计测试,以使其满足三个条件。 我们希望我们的测试套件

  1. Correct. They should not only compile and run properly, but they should isolate and evaluate a single function output with accuracy.

    正确。 它们不仅应正确编译和运行,而且应准确地隔离和评估单个函数输出。
  2. Thorough. The test suite should cover the entire input space, with the input space being anything that your user or program could input into a given function.

    彻底。 测试套件应覆盖整个输入空间,而输入空间是您的用户或程序可以输入给定功能的任何空间。
  3. Small. Refer to the great conflict of testing. No one wants to write tests, so we try to design them so that we can ensure quality and coverage whilst avoiding unnecessary tests. Also, they will be faster to run and easier to update, making testing easier going forward.

    小。 请参阅测试的巨大冲突。 没有人愿意编写测试,因此我们尝试设计它们,以确保质量和覆盖范围,同时避免不必要的测试。 而且,它们将更快地运行并且更容易更新,从而使测试更容易进行。

如何编写测试 (How to write tests)

So you understand what makes a good, systematic test suite, and you understand the importance of doing so, but how do you actually write them?

因此,您了解了什么可以构成一个好的系统的测试套件,并且了解了这样做的重要性,但是如何实际编写它们呢?

You want to be brutal.

你想残酷。

As a test suite designer, your life is pretty rough, and you basically want to take it all out on the program. You want to make it fail as fast as you can, and you do this by poking at its insecurities. These insecurities, unlike a person’s, can be fixed with relative ease, but only if you write effective tests. Tests, in the end, are there to ensure functionality if your program passes, and make it easy to find what went wrong if your program fails.

作为测试套件设计人员,您的生活相当艰难,并且您基本上希望在程序中全力以赴。 您想使它尽可能快地失败,然后戳它的不安全性来做到这一点。 与人不同,这些不安全感可以相对轻松地解决,但前提是您编写有效的测试。 最后,测试可以确保程序通过后的功能,并且可以轻松找到程序失败的原因。

For actually coming up with tests, you want to start with your input space. To cover the input space in an efficient manner, it’s easiest to divide it into subdomains where the program acts similarly among every input in the subdomain. Then you can write a single test for each subdomain and cover the whole input space. But don’t forget, that your input space also includes boundary/edge cases. These are the special cases in your program that often occur with null or empty values, first and last elements of lists, and other “boundaries” between spaces. Although they cover much smaller sections of your input space, they are just as important.

为了真正提出测试,您需要从输入空间开始。 为了有效地覆盖输入空间,最简单的方法是将其划分为子域,在该子域中,程序在子域中的每个输入之间的行为类似。 然后,您可以为每个子域编写一个测试,并覆盖整个输入空间。 但是请不要忘记,您的输入空间还包括边界/边沿情况。 这些是程序中的特殊情况,通常会出现空值或空值,列表的第一个和最后一个元素以及空格之间的其他“边界”。 尽管它们覆盖了输入空间的较小部分,但它们同样重要。

黑盒与玻璃盒测试 (Black box vs. glass box testing)

It sounds simple to just cover the input space, but sometimes there is a bit of ambiguity in what that exactly means. In my first assignment in my software design class, we were given the task of testing and implementing a tic tac toe board evaluator. Some of the test cases included testing whether it correctly evaluated a win for X, a win for O, a draw, etc.

仅仅覆盖输入空间听起来很简单,但是有时这在确切含义上有些含糊。 在我的软件设计课程的第一个任务中,我们承担了测试和实施井字游戏评估板的任务。 一些测试用例包括测试它是否正确评估了X的胜利,O的胜利,平局等。

However, when it came time to test some of these things, I had I needed to test if it recognized a win in any row, and I was tasked with the decision as to whether I should write a test to ensure it checked every row, or just a single test evaluating a single arbitrary row. In a relatively small project like this, it is not much work to write a couple more tests to ensure accuracy, but it becomes trickier the larger and more complicated real software can be.

但是,当需要测试其中一些内容时,我需要测试它是否在任何行中都获胜,并且我的任务是决定是否应该编写测试以确保它检查每一行,或仅是一个评估单个任意行的测试。 在这样一个相对较小的项目中,要编写更多的测试来确保准确性并不需要太多工作,但是,更大更复杂的真实软件可能变得更加棘手。

This is where it’s helpful to understand the distinction between black box and glass box testing.

在这里,有助于了解黑盒测试和玻璃盒测试之间的区别。

Black box testing is writing tests without knowing how the function is implemented. This means you can’t use shortcuts to test different conditions in your function, and so it usually ends up with more tests. It also means that if you or another developer changes the function in the future, that the tests will need little to no changes to still ensure accuracy across the input space.

黑匣子测试是在不知道功能如何实现的情况下编写测试。 这意味着您不能使用快捷方式来测试函数中的不同条件,因此通常会进行更多测试。 这也意味着,如果您或其他开发人员将来更改功能,则测试几乎不需要更改,甚至不需要更改即可确保输入空间的准确性。

In an ideal world, we could seamlessly integrate black box testing for all of our testing needs, but in reality, it usually is more of a combination between black box, and glass box testing.

在理想的世界中,我们可以无缝集成黑盒测试以满足所有测试需求,但实际上,通常更多是黑盒测试和玻璃盒测试的结合。

With glass box testing, you can see through the glass and into how your function works. In my tic tac toe example, I knew that my program looped through every row, and so I didn’t end up writing extra tests for each row. But if someone were to change the implementation because it was faster or more efficient somehow to check rows manually, then having a test for each row would have been valuable.

通过玻璃箱测试,您可以透视玻璃并了解其功能。 在我的井字游戏示例中,我知道我的程序遍历了每一行,因此我并没有最终为每一行编写额外的测试。 但是,如果有人因为手动检查行的速度更快或更有效而更改了实现,那么对每一行进行测试将非常有价值。

Glass box testing isn’t all bad. It allows you to more intentionally poke at specific areas and often more efficiently write tests for your code. It just also comes at the tradeoff of being less sustainable for changes in the implementation.

玻璃箱测试并非一无是处。 它使您可以更有针对性地戳特定区域,并且通常可以更有效地为代码编写测试。 这也只是权衡了实施变更的可持续性。

In the end, it’s up to you as the developer to read the situation and determine what is most valuable for your software.

最后,由开发人员自行决定阅读情况并确定对您的软件最有价值的东西。

测试优先编程 (Test-first programming)

With testing, it is most effective to design your functions and write the tests and specifications for your functions before implementing them. Going about the development process in this order or writing the spec, test, then implementation is referred to as test-first programming, and it prevents a lot of stress and frustration while debugging down the line.

使用测试,最有效的方法是设计功能并在实现之前编写功能的测试和规格。 按此顺序进行开发过程或编写规范,进行测试,然后将其实现称为测试优先编程,它可以防止调试过程中的大量压力和挫败感。

Through this process, you can isolate functions and ensure accuracy along the way, so in the future when something goes wrong, you don’t have to think about if any of these many previous functions have problems. It makes debugging much easier, and as a system overall it keeps the development process more organized and intentional.

通过此过程,您可以隔离功能并确保过程中的准确性,因此在将来出现问题时,您不必考虑许多以前的功能是否有问题。 它使调试变得更加容易,并且作为一个整体的系统,它使开发过程更加有组织和有目的。

In a simple project like my tic tac toe board evaluator, test-first programming sounds like a brilliant and elegant software development practice, but when the school year picks up and things get more complex, it becomes more and more tempting to save tests for last.

在像我的井字棋评估板这样的简单项目中,测试优先编程听起来像是一种出色而优雅的软件开发实践,但是当学年加快并且事情变得越来越复杂时,保存测试以保存最后的测试变得越来越诱人。

我对最后测试编程的经验 (My experience with test-last programming)

In my most recent assignment in my software design class, I did what I call test-last programming. And although most of the time I could understand whether my code worked by haphazardly testing some cases while running it, I ended up redesigning and reimplementing significant portions of the program several times. Not only did this take tons of extra time, but as I rewrote my program for the third time, I had lost my excitement and enthusiasm I originally had for the assignment. I’d set myself up for disaster by not implementing good software practices and I was facing the consequences.

在我最近一次软件设计课程中,我做了所谓的测试最后编程。 而且尽管大部分时间我可以通过在运行时偶然测试某些案例来了解我的代码是否有效,但最终还是多次重新设计并重新实现了程序的重要部分。 这不仅花费了很多额外的时间,而且当我第三次重写程序时,我失去了原本对任务的兴奋和热情。 我没有实施良好的软件实践就使自己陷入灾难,而我正面临后果。

Test-first programming means that you design and write the specs for each function of the program from the beginning, so you get a thorough picture of how everything will work together, and you get it all out of your brain and into your program. Through this, you can catch design problems early on, and not need to waste energy rethinking and questioning fundamental aspects of your program.

测试优先编程意味着您从一开始就设计和编写程序的每个功能的规范,因此您可以全面了解所有功能如何协同工作,并且一切都从脑中进入程序。 这样,您可以及早发现设计问题,而无需浪费精​​力重新思考和质疑程序的基本方面。

Here, test-first programming wouldn’t have helped me out explicitly through the design of my tests, but by thinking about development with a testing mindset, I could have served myself better in the long term development process.

在这里,测试优先编程不会通过测试的设计来明确地帮助我,但是通过考虑测试心态进行开发,我可以在长期开发过程中为自己提供更好的服务。

While in the midst of some deep, focused programming and in living life in general we will always be subject to unexpected problems, but through test-first programming, when we need water, we can focus on fixing the shower without worrying about broken pipes.

虽然在一些深入,专注的程序设计中以及一般的生活中,我们总是会遇到意想不到的问题,但是通过测试优先程序设计,当我们需要水时,我们可以专注于固定淋浴器而不必担心管子破裂。

翻译自: https://medium/swlh/a-crash-course-on-software-testing-but-interesting-8cbe007e021b

软件测试速成

本文标签: 测试软件但很有趣课程