Maison  >  Article  >  interface Web  >  Pensez à protéger vos clients !

Pensez à protéger vos clients !

王林
王林original
2023-09-07 13:49:051249parcourir

En vous assurant que votre application est testée, vous pouvez réduire le nombre de bugs trouvés dans votre code, améliorer la maintenabilité de votre application et concevoir un code bien structuré.

Les tests unitaires côté client présentent des défis différents de ceux des tests côté serveur. Lorsque vous travaillez avec du code côté client, vous aurez du mal à séparer la logique d'application de la logique DOM et vous vous contenterez souvent de créer du code JavaScript. Heureusement, il existe de nombreuses excellentes bibliothèques de tests côté client qui peuvent vous aider à tester votre code, à créer des métriques sur la couverture des tests et à analyser sa complexité.


Pourquoi tester ?

Tout d'abord, les tests unitaires sont souvent un moyen de réduire les erreurs en garantissant que l'application se comporte comme prévu. En dehors de cela, il existe également les concepts de Test Driven Development (TDD) et de Behaviour Driven Development (BDD).

Ces deux stratégies de tests unitaires vous aideront à concevoir votre application en écrivant des tests avant d'écrire la logique de l'application. En écrivant des tests avant d’écrire du code, vous aurez l’occasion de bien réfléchir à la conception de votre application.

Cela se produit parce que lorsque vous écrivez des tests, vous essayez essentiellement de concevoir l'API avec laquelle le code interagit, afin de mieux comprendre sa conception. Les tests en premier révéleront rapidement tout défaut de conception, car le code de test que vous écrivez utilise essentiellement le code que vous écrivez !

TDD est un processus de découverte de code

Vous apprendrez que TDD vous aide à découvrir le code au fur et à mesure que vous l'écrivez. TDD peut rapidement être résumé par « Rouge, Vert, Refactor ». Cela signifie que vous écrivez un test, écrivez suffisamment de code pour que le test échoue en premier lieu. Ensuite, vous écrivez le code qui fait réussir le test. Ensuite, vous réfléchissez bien à ce que vous venez d’écrire et vous le reconstruisez. Agréable et facile.

BDD est légèrement différent de TDD et est davantage basé sur les exigences et les spécifications de l'entreprise.


Test client

Il existe de nombreuses raisons pour lesquelles vous devriez tester votre code client. Comme mentionné précédemment, cela contribuera à réduire les erreurs et vous aidera à concevoir votre application. Les tests côté client sont également importants car ils vous donnent la possibilité de tester le code frontal de manière indépendante, en dehors de la présentation. En d’autres termes, l’un de ses avantages est que vous pouvez tester du code JavaScript sans réellement démarrer le serveur d’applications. Au lieu de cliquer et de tester, vous pouvez simplement exécuter les tests et vous assurer que la fonctionnalité fonctionne. Dans de nombreux cas, vous n'avez même pas besoin d'un accès Internet tant que vous configurez correctement votre test.

Le JavaScript jouant un rôle si important dans le développement Web moderne, il est important d'apprendre à tester votre code et à réduire le risque que des bogues se retrouvent dans le code de production. Votre patron n’aime pas que cela se produise, et vous ne devriez pas non plus le faire ! En fait, un bon point de départ pour les tests côté client consiste à écrire des tests autour du rapport d’erreurs. Cela vous permettra de vous entraîner à rédiger des tests lorsque vous n'avez nulle part où repartir de zéro.

Une autre raison de tester le code client est qu'une fois qu'une suite de tests existe et que vous disposez d'une couverture appropriée de votre code, vous pourrez ajouter de nouvelles fonctionnalités, réexécuter vos tests lorsque vous serez prêt à ajouter de nouvelles fonctionnalités à votre code, et assurez-vous de ne pas dégrader ou interrompre les fonctionnalités existantes.


Commencer

Si vous n'avez jamais effectué de tests clients auparavant, se lancer dans les tests clients peut être intimidant. L'une des parties les plus difficiles des tests côté client consiste à trouver le meilleur moyen d'isoler le DOM de la logique de l'application. Cela signifie généralement que vous avez besoin d'une sorte d'abstraction sur le DOM. Le moyen le plus simple d'y parvenir consiste à utiliser un framework côté client tel que Knockout.js, Backbone.js ou Angular.js, pour n'en nommer que quelques-uns.

Lorsque vous utilisez une bibliothèque comme celle-ci, vous pouvez moins penser à la façon dont votre page s'affiche dans le navigateur et davantage aux fonctionnalités de votre application. Cependant, les tests unitaires avec du JavaScript simple ne sont pas impossibles. Dans ce cas, votre vie sera beaucoup plus facile si vous concevez votre code de manière à ce que le DOM puisse être facilement abstrait.

Sélectionnez la bibliothèque de tests

Il existe de nombreuses bibliothèques de tests différentes parmi lesquelles choisir, bien que les trois leaders soient généralement QUnit, Mocha et Jasmine.

Jasmine et Mocha viennent tous deux de l'école de tests unitaires BDD, tandis que QUnit n'est qu'un framework de tests unitaires à part entière.

Dans le reste de cet article, nous explorerons l'utilisation de QUnit car il présente une très faible barrière à l'entrée dans les tests clients. Voir l'introduction détaillée de QUnit pour plus d'informations.

Utilisez QUnit TDD votre code

Démarrer avec QUnit est très simple. Tout ce dont vous avez besoin est le code HTML suivant :

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>QUnit Example</title>
    <link rel="stylesheet" href="qunit.css">
</head>
<body>
    <div id="qunit"></div>
    <div id="qunit-fixture"></div>
    <script src="qunit.js"></script>
    <script src="../app/yourSourceCode.js"></script>
    <script src="tests.js"></script>
</body>
</html>

Pour les prochains exemples, disons que nous construisons un widget qui vous permet de saisir un code postal dans une zone de texte et qui renvoie les valeurs correspondantes de la ville, de l'état et du comté à l'aide de Geonames. Il affiche uniquement le code postal au début, mais une fois que le code postal comporte cinq caractères, il récupère les données de Geonames. Si les données peuvent être trouvées, davantage de champs seront affichés contenant les informations résultantes sur la ville, l'état et le comté. Nous utiliserons également Knockout.js. La première étape consiste à écrire des tests qui échouent.

Réfléchissez un peu au design avant d'écrire votre premier test, vous aurez probablement besoin d'au moins deux viewModels, ce serait donc un bon point de départ. Tout d'abord, nous allons définir un module QUnit et notre premier test :

module("zip code retriever");
test("view models should exist", function() {
    ok(FormViewModel, "A viewModel for our form should exist");
    ok(AddressViewModel, "A viewModel for our address should exist");
});

如果你运行这个测试,它会失败,现在你可以编写代码让它通过:

Pensez à protéger vos clients !

var AddressViewModel = function(options) {

};

var FormViewModel = function() {
    this.address = new AddressViewModel();
};

这次您会看到绿色而不是红色。像这样的测试乍一看有点愚蠢,但它们很有用,因为它们迫使您至少思考设计的一些早期阶段。

Pensez à protéger vos clients !

我们将编写的下一个测试将适用于 AddressViewModel 的功能。从这个小部件的规范中我们知道,其他字段应该首先隐藏,直到找到邮政编码的数据。

module("address view model");
test("should show city state data if a zip code is found", function() {
    var address = new AddressViewModel();

    ok(!address.isLocated());

    address.zip(12345);
    address.city("foo");
    address.state("bar");
    address.county("bam");

    ok(address.isLocated());
});

尚未编写任何代码,但这里的想法是 isLocated 将是一个计算的可观察值,仅当邮政编码、城市、州和县时才返回 true都是实话。所以,这个测试一开始当然会失败,现在让我们编写代码让它通过。

var AddressViewModel = function(options) {
    options = options || {};

    this.zip = ko.observable(options.zip);
    this.city = ko.observable(options.city);
    this.state = ko.observable(options.state);
    this.county = ko.observable(options.county);

    this.isLocated = ko.computed(function() {
        return this.city() && this.state() && this.county() && this.zip();
    }, this);

    this.initialize();
};

现在,如果您再次运行测试,您将看到绿色!

这是最基本的,如何使用 TDD 编写前端测试。理想情况下,在每次失败的测试之后,您应该编写最简单的代码来使测试通过,然后返回并重构代码。不过,您可以了解更多有关 TDD 实践的知识,因此我建议您进一步阅读并研究它,但前面的示例足以让您考虑首先编写测试。

使用Sinon.js模拟依赖关系

Sinon.js 是一个 JavaScript 库,提供监视、存根和模拟 JavaScript 对象的功能。编写单元测试时,您希望确保只能测试给定的代码“单元”。这通常意味着您必须对依赖项进行某种模拟或存根以隔离正在测试的代码。

Sinon 有一个非常简单的 API 可以完成此操作。 Geonames API 支持通过 JSONP 端点检索数据,这意味着我们将能够轻松使用 $.ajax

理想情况下,您不必在测试中依赖 Geonames API。它们可能会暂时关闭,您的互联网可能会中断,并且实际进行 ajax 调用的速度也会变慢。诗乃前来救援。

test("should only try to get data if there's 5 chars", function() {
    var address = new AddressViewModel();

    sinon.stub(jQuery, "ajax").returns({
        done: $.noop
    });

    address.zip(1234);

    ok(!jQuery.ajax.calledOnce);

    address.zip(12345);

    ok(jQuery.ajax.calledOnce);

    jQuery.ajax.restore();
});

在此测试中,我们做了一些事情。首先,sinon.stub 函数实际上将代理 jQuery.ajax 并添加查看其被调用次数以及许多其他断言的功能。正如测试所示,“应该仅在有 5 个字符时尝试获取数据”,我们假设当地址设置为“1234”时,尚未进行 ajax 调用,然后将其设置为“12345”,此时应进行 ajax 调用。

然后我们需要将 jQuery.ajax 恢复到其原始状态,因为我们是单元测试的好公民,并且希望保持我们的测试原子性。保持测试的原子性非常重要,可以确保一个测试不依赖于另一测试,并且测试之间不存在共享状态。然后它们也可以按任何顺序运行。

现在测试已经编写完毕,我们可以运行它,观察它失败,然后编写向 Geonames 执行 ajax 请求的代码。

AddressViewModel.prototype.initialize = function() {
    this.zip.subscribe(this.zipChanged, this);
};

AddressViewModel.prototype.zipChanged = function(value) {
    if (value.toString().length === 5) {
        this.fetch(value);
    }
};

AddressViewModel.prototype.fetch = function(zip) {
    var baseUrl = "http://www.geonames.org/postalCodeLookupJSON"

    $.ajax({
        url: baseUrl,
        data: {
            "postalcode": zip,
            "country": "us"
        },
        type: "GET",
        dataType: "JSONP"
    }).done(this.fetched.bind(this));
};

在这里,我们订阅邮政编码的更改。每当它发生变化时,都会调用 zipChanged 方法。 zipChanged 方法将检查 zip 值的长度是否为 5。当到达 5 时,将调用 fetch 方法。这就是Sinon 存根发挥作用的地方。此时,$.ajax实际上是一个Sinon存根。因此,在测试中 CalledOnce 将是 true

我们将编写的最终测试是数据从 Geonames 服务返回时的情况:

test("should set city info based off search result", function() {
    var address = new AddressViewModel();

    address.fetched({
        postalcodes: [{
            adminCode1: "foo",
            adminName2: "bar",
            placeName: "bam"
        }]
    });

    equal(address.city(), "bam");
    equal(address.state(), "foo");
    equal(address.county(), "bar");
});

此测试将测试如何将来自服务器的数据设置到 AddressViewmodel 上。运行一下,看到一些红色。现在将其设为绿色:

AddressViewModel.prototype.fetched = function(data) {
    var cityInfo;

    if (data.postalcodes && data.postalcodes.length === 1) {
        cityInfo = data.postalcodes[0];

        this.city(cityInfo.placeName);
        this.state(cityInfo.adminCode1);
        this.county(cityInfo.adminName2);
    }
};

fetched方法只是确保从服务器传来的数据中有一个postalcodes数组,然后在viewModel上设置相应的属性。

看看这现在有多容易了吗?一旦你掌握了执行此操作的流程,你就会发现自己几乎不想再进行 TDD。您最终会得到可测试的漂亮小函数。您强迫自己思考代码如何与其依赖项交互。现在,当代码中添加其他新需求时,您可以运行一套测试。即使您错过了某些内容并且代码中存在错误,您现在也可以简单地向套件添加新测试,以证明您已经修复了错误!它实际上最终会让人上瘾。


测试覆盖率

测试覆盖率提供了一种简单的方法来评估单元测试测试了多少代码。达到 100% 的覆盖率通常很困难且不值得,但请尽您所能使其尽可能高。

更新且更简单的覆盖库之一称为 Blanket.js。将它与 QUnit 一起使用非常简单。只需从他们的主页获取代码或使用 Bower 安装即可。然后将毯子添加为 qunit.html 文件底部的库,然后将 data-cover 添加到您想要进行覆盖率测试的所有文件。

    <script src="../app/yourSourceCode.js" data-cover></script>
    <script src="../js/lib/qunit/qunit/qunit.js"></script>
    <script src="../js/lib/blanket/dist/qunit/blanket.js"></script>
    <script src="tests.js"></script>
</body>

完成。超级简单,现在您将在 QUnit 运行程序中获得一个用于显示覆盖范围的选项:

Pensez à protéger vos clients !

在此示例中,您可以看到测试覆盖率并不是 100%,但在这种情况下,由于代码不多,因此很容易提高覆盖率。您实际上可以深入了解尚未涵盖的确切功能:

Pensez à protéger vos clients !

在这种情况下,FormViewModel 从未在测试中实例化,因此缺少测试覆盖率。然后,您可以简单地添加一个新测试来创建 FormViewModel 的实例,并且可能编写一个断言来检查 address 属性是否存在并且是 instanceOf AddressViewModel

然后您将很高兴看到 100% 的测试覆盖率。

Pensez à protéger vos clients !


复杂性测试

随着您的应用程序变得越来越大,能够对 JavaScript 代码运行一些静态分析是件好事。 Plato 是一个在 JavaScript 上运行分析的好工具。

您可以通过 npm 安装来运行 plato

npm install -g plato

然后您可以在 JavaScript 代码目录上运行 plato

plato -r -d js/app reports

这将在位于“js/app”的所有 JavaScript 上运行 Plato,并将结果输出到 reports。 Plato 对您的代码运行各种指标,包括平均代码行数、计算的可维护性分数、JSHint、难度、估计错误等等。

Pensez à protéger vos clients !

在上一张图片中没有太多可看的内容,仅仅是因为对于我们一直在处理的代码来说,只有一个文件,但是当您开始使用具有大量文件的大型应用程序时,几行代码,您会发现它为您提供的信息非常有用。

它甚至会跟踪您运行它的所有时间,以便您可以查看统计数据如何随时间变化。

结论

虽然测试客户端似乎是一个困难的提议,但现在有很多很棒的工具可以使用,使它变得超级简单。本文仅仅触及了当今所有使客户端测试变得容易的事情的表面。这可能是一项乏味的任务,但最终您会发现,拥有测试套件和可测试代码的好处远远超过它。希望通过此处概述的步骤,您将能够快速开始测试客户端代码。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn