gpt4 book ai didi

javascript - JavaScript Web 前端的测试驱动开发

转载 作者:IT王子 更新时间:2023-10-29 03:17:30 25 4
gpt4 key购买 nike

这听起来可能有点愚蠢,但实际上我对如何处理 Web 前端的 JavaScript 测试有点困惑。就我而言,典型的 3 层架构如下所示:

  1. 数据库层
  2. 应用层
  3. 客户端

1 在这个问题中无关紧要。 2 包含所有程序逻辑(“业务逻辑”) 3 前端。

我为大多数项目做测试驱动开发,但只针对应用程序逻辑,而不是前端。这是因为在 TDD 中测试 UI 很困难且不常见,而且通常不会这样做。相反,所有应用程序逻辑都与 UI 分离,因此测试该逻辑很简单。

三层架构支持这一点:我可以将后端设计为由前端调用的 REST API。 JS测试如何适应?对于典型的三层架构,JS(即客户端上的 JS)测试没有多大意义,是吗?

更新:我已将问题的措辞从“在 Web 前端测试 JavaScript”更改为“JavaScript Web 前端的测试驱动开发”以澄清我的问题。

最佳答案

记住单元测试的意义是什么:确保特定的代码模块以预期的方式对某些刺激使用react。在 JS 中,代码的很大一部分(除非你有像 Sencha 或 YUI 这样的生命周期框架)将直接操作 DOM 或进行远程调用。要测试这些东西,您只需应用依赖注入(inject)和模拟/ stub 的传统单元测试技术。这意味着您必须编写要进行单元测试的每个函数或类,以接受依赖结构的模拟。

jQuery 通过允许您将 XML 文档传递给所有遍历函数来支持这一点。而你通常会写

$(function() { $('.bright').css('color','yellow'); }

你会想写

function processBright(scope) {
// jQuery will do the following line automatically, but for sake of clarity:
scope = scope || window.document;

$('.bright',scope).css('color','yellow');
}

$(processBright);

请注意,我们不仅将逻辑从匿名函数中提取出来并为其命名,我们还让该函数接受一个范围参数。当该值为 null 时,jQuery 调用仍将正常运行。但是,我们现在有一个用于注入(inject)模拟文档的向量,我们可以在调用函数后检查该文档。单元测试看起来像

function shouldSetColorYellowIfClassBright() {
// arrange
var testDoc =
$('<html><body><span id="a" class="bright">test</span></body></html>');

// act
processBright(testDoc);

// assert
if (testDoc.find('#a').css('color') != 'bright')
throw TestFailed("Color property was not changed correctly.");
}

TestFailed 可能如下所示:

function TestFailed(message) {
this.message = message;
this.name = "TestFailed";
}

情况与远程调用类似,但您可以使用屏蔽 stub 而不是实际注入(inject)一些设施。假设你有这个功能:

function makeRemoteCall(data, callback) {
if (data.property == 'ok')
$.getJSON({url:'/someResource.json',callback:callback});
}

你会这样测试它:

// test suite setup
var getJSON = $.getJSON;
var stubCalls = [];
$.getJSON = function(args) {
stubCalls[stubCalls.length] = args.url;
}

// unit test 1
function shouldMakeRemoteCallWithOkProperty() {
// arrange
var arg = { property: 'ok' };

// act
makeRemoteCall(arg);

// assert
if (stubCalls.length != 1 || stubCalls[0] != '/someResource.json')
throw TestFailed("someResource.json was not requested once and only once.");
}

// unit test 2
function shouldNotMakeRemoteCallWithoutOkProperty() {
// arrange
var arg = { property: 'foobar' };

// act
makeRemoteCall(arg);

// assert
if (stubCalls.length != 0)
throw TestFailed(stubCalls[0] + " was called unexpectedly.");
}

// test suite teardown
$.getJSON = getJSON;

(您可以将整个内容包装在 module pattern 中,以免弄乱全局命名空间。)

要以测试驱动的方式应用所有这些,您只需先编写这些测试即可。这是一种简单、简洁、最重要的是有效的 JS 单元测试方法。

像 qUnit 这样的框架可以用来驱动你的单元测试,但这只是问题的一小部分。您的代码必须以易于测试的方式编写。此外,Selenium、HtmlUnit、jsTestDriver 或 Watir/N 等框架用于集成测试,而不是用于单元测试本身。最后,您的代码绝不必须是面向对象的。单元测试的原理很容易与单元测试在面向对象系统中的实际应用相混淆。它们是独立但兼容的想法。

测试风格

我应该注意到这里展示了两种不同的测试风格。第一个假设完全不知道 processBright 的实现。它可以使用 jQuery 添加颜色样式,也可以进行原生 DOM 操作。我只是在测试函数的外部行为是否符合预期。在第二种情况下,我假设了解函数的内部依赖性(即 $.getJSON),并且这些测试涵盖与该依赖性的正确交互

您采用的方法取决于您的测试理念和总体优先级以及您的情况的成本效益概况。第一次测试比较纯粹。第二个测试简单但相对脆弱;如果我更改 makeRemoteCall 的实现,测试将会中断。最好,makeRemoteCall 使用 $.getJSON 的假设至少由 makeRemoteCall 的文档证明是合理的。还有一些更严格的方法,但一种经济高效的方法是将依赖项包装在包装函数中。代码库将仅依赖于这些包装器,其实现可以在测试时轻松替换为测试 stub 。

关于javascript - JavaScript Web 前端的测试驱动开发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5514466/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com