> 웹 프론트엔드 > JS 튜토리얼 > 실행 가능한 JavaScript 사양을 구축하는 방법에 대한 자세한 설명

실행 가능한 JavaScript 사양을 구축하는 방법에 대한 자세한 설명

青灯夜游
풀어 주다: 2020-10-23 17:57:37
앞으로
1822명이 탐색했습니다.

실행 가능한 JavaScript 사양을 구축하는 방법에 대한 자세한 설명

프로그래밍은 단순히 작업을 완료하는 방법을 컴퓨터에 지시하는 것 이상이며, 다른 사람, 심지어 미래의 자신과 정확한 방식으로 아이디어를 전달하는 것이기도 합니다. 그러한 의사소통에는 정보를 공유하거나 수정을 더 쉽게 만드는 등 여러 가지 목표가 있을 수 있습니다. 오래 전에 수행된 작업을 이해하거나 기억하지 못한다면 이는 어려운 일입니다.

소프트웨어를 작성할 때 코드에 의도한 기능이 있는지도 확인해야 합니다. 의미론을 정의하는 공식적인 방법이 있지만 가장 간단하고 빠른(그러나 덜 엄격한) 접근 방식은 기능을 사용하고 예상 결과가 생성되는지 확인하는 것입니다.

대부분의 개발자는 코드 블록의 목표를 명확히 하기 위한 주석으로 코드를 문서화하고, 함수가 원하는 출력을 제공하는지 확인하는 일련의 테스트와 같은 방식에 익숙합니다.

그러나 일반적으로 문서화와 테스트는 서로 다른 단계로 수행됩니다. 이러한 관행을 통합함으로써 프로젝트 개발에 참여하는 모든 사람에게 더 나은 경험을 제공할 수 있습니다. 이 기사에서는 문서화와 테스트 모두에 적합한 JavaScript 사양을 실행할 수 있는 간단한 프로그램의 구현을 살펴봅니다.

디렉토리에서 모든 사양 파일을 찾고, 각 사양에서 발견된 모든 주장을 추출하고, 결과를 계산하여 최종적으로 어떤 주장이 실패했고 어떤 주장이 통과했는지 보여주는 명령줄 인터페이스를 구축하겠습니다.

표준 형식

각 표준 파일은 템플릿 텍스트에서 문자열을 내보냅니다. 첫 번째 줄은 사양의 제목 역할을 할 수 있습니다. 템플릿 리터럴을 사용하면 문자열 사이에 JS 표현식을 삽입할 수 있으며 각 표현식은 주장을 나타냅니다. 각 주장을 식별하기 위해 고유한 문자로 줄을 시작할 수 있습니다.

이 경우 막대 문자(|)와 대시(-)를 조합하여 사용할 수 있습니다. 대시는 회전문 기호와 유사하며 때로는 논리적 주장을 위한 기호로 표시될 수도 있습니다.

다음은 사용법에 대한 설명이 포함된 예입니다.

const dependency = require('./dependency')module.exports = `
  Example of a Specification File
  
  This project allows to test JavaScript programs using specification files.
  Every *.spec.js file exports a single template literal that includes a general
  explanation of the file being specified. Each file represents a logical
  component of a bigger system. Each logical component is composed of several
  units of functionality that can be tested for certain properties.
  Each one of this units of functionality may have one or more
  assertions. Each assertion is denoted by a line as the following:

  |- ${dependency} The dependency has been loaded and the first assert has
  been evaluated.

  Multiple assertions can be made for each file:

  |- ${false} This assertion will fail.

  |- ${2 + 2 === 4} This assertion will succeed.

  The combination of | and - will form a Turnstile ligature (|-) using the appropriate
  font. Fira Code is recommended. A Turnstile symbol was used by Gottlob Frege
  at the start of sentenses being asserted as true.

  The intended usage is for specification-first software. Where the programmer
  defines the high level structure of a program in terms of a specification,
  then progressively builds the parts conforming that specification until all
  the tests are passed. A desired side-effect is having a simple way to generate
  up-to-date documentation outside the code for API consumers.
`
로그인 후 복사

이제 프로그램의 상위 수준 구조로 넘어가겠습니다.

우리 프로그램의 구조

우리 프로그램의 전체 구조는 몇 줄의 코드로 정의할 수 있으며 두 개의 Node.js 라이브러리를 사용하여 파일 시스템(fs)과 디렉터리 경로(path)를 처리하는 것 외에는 아무것도 없습니다. . 이 섹션에서는 프로그램의 구조만 정의하고, 함수 정의는 다음 섹션에서 제공됩니다.

#!/usr/bin/env node
const fs = require('fs')
const path = require('path')
const specRegExp = /\.spec\.js$/
const target = path.join(process.cwd(), process.argv[2])
// Get all the specification file paths
// If a specification file is provided then just test that file
// Otherwise find all the specification files in the target directory
const paths = specRegExp.test(target)
  ? [ target ]
  : findSpecifications(target, specRegExp).filter(x => x)
// Get the content of each specification file
// Get the assertions of each specification file
const assertionGroups = getAssertions(getSpecifications(paths))
// Log all the assertions
logAssertions(assertionGroups)
 
// Check for any failed assertions and return an appropriate exit code
process.exitCode = checkAssertions(assertionGroups)
로그인 후 복사

이것은 CLI(명령줄 인터페이스)의 진입점이기도 하므로 이 파일이 노드 프로그램에 의해 실행되어야 함을 나타내는 shebang의 첫 번째 줄을 추가해야 합니다. 단일 인수에만 관심이 있으므로 명령 옵션을 처리하기 위해 특정 라이브러리를 추가할 필요가 없습니다. 그러나 이 프로그램을 대폭 확장할 계획이라면 다른 옵션을 고려해 볼 수도 있습니다.

대상 테스트 파일이나 디렉터리를 얻으려면 명령을 실행할 때(process.argv[2 사용) 첫 번째 인수로 사용자 제공 인수와 명령을 실행할 경로(process.cwd() 사용)를 연결해야 합니다. ]) .

프로세스 개체에 대한 Node.js 문서에서 이러한 값에 대한 참조를 찾을 수 있습니다. 이 방법으로 우리는 대상 디렉터리/파일의 절대 경로를 얻습니다.

이제 가장 먼저 해야 할 일은 모든 JavaScript 사양 파일을 찾는 것입니다. 12행에 표시된 대로 조건 연산자를 사용하여 더 많은 유연성을 제공할 수 있습니다. 사용자가 표준 파일을 대상으로 제공하는 경우 파일 경로를 직접 사용하면 됩니다.

그렇지 않고 사용자가 디렉토리 경로를 제공하면 specRegExp에 정의된 상수와 일치하는 모든 파일을 찾아야 하며, 이는 나중에 정의할 findSpecifications 함수를 사용합니다. 이 함수는 대상 디렉터리의 각 사양 파일에 대한 경로 배열을 반환합니다.

라인 18에서는 getspecation() 및 getassertion() 두 함수를 결합하여 AssertionGroups 상수를 정의합니다. 먼저 각 사양 파일의 콘텐츠를 가져온 다음 여기에서 어설션을 추출합니다.

이 두 함수는 나중에 정의할 것입니다. 지금은 첫 번째 함수의 출력을 두 번째 함수의 매개변수로 사용하여 프로세스를 단순화하고 두 함수 connect 사이에 직접적인 연결을 설정한다는 점만 참고하세요.

하나의 기능만 가질 수 있고 이를 분할함으로써 실제 프로세스가 무엇인지 더 잘 알 수 있지만, 프로그램은 명확하고 이해하기 쉬워야 한다는 점을 기억하세요.

assertionsGroup 상수는 다음과 같이 구성됩니다:

assertionGroup[specification][assertion]
로그인 후 복사

다음으로, logassertion() 함수를 사용하여 결과를 보고할 수 있도록 이러한 모든 주장을 사용자 로그에 기록합니다. 각 주장에는 결과(참 또는 거짓)와 간단한 설명이 포함되며, 이 정보를 사용하여 각 결과 유형에 특별한 색상을 부여할 수 있습니다.

마지막으로 어설션 결과에 따라 종료 코드를 정의합니다. 이는 프로그램이 어떻게 종료되었는지에 대한 정보를 프로세스에 제공합니다. 프로세스가 성공했습니까 아니면 실패했습니까? 종료 코드 0은 프로세스가 성공적으로 종료되었음을 의미하고, 실패하면 1이고, 이 예에서는 하나 이상의 어설션이 실패했을 때 1입니다.

모든 사양 문서 찾기

要找到所有的JavaScript规范文件,我们可以使用一个递归函数,该函数遍历用户作为CLI参数指定的目录。在搜索时,应该使用程序开始时定义的正则表达式(/\.spec\.js$/)检查每个文件,该表达式将匹配以.spec.js结尾的所有文件路径。

function findSpecifications (dir, matchPattern) {
  return fs.readdirSync(dir)
    .map(filePath => path.join(dir, filePath))
    .filter(filePath => matchPattern.test(filePath) && fs.statSync(filePath).isFile())
}
로그인 후 복사

我们的findspecification函数接受一个目标目录(dir)和一个正则表达式,该正则表达式标识规范文件(matchPattern)。

获取每个规范的内容

由于我们导出的是模板文本,因此获取内容和计算后的断言非常简单,因此我们必须导入每个文件,当它被导入时,所有的断言都将自动进行计算。

function getSpecifications (paths) {
  return paths.map(path => require(path))
}
로그인 후 복사

使用map()函数,我们使用节点的require函数将数组的路径替换为文件的内容。

从文本中提取断言

此时,我们有一个数组,其中包含每个规范文件的内容,并且已经计算了它们的断言。我们使用旋转门指示器(|-)来查找所有这些断言并提取它们。

function getAssertions (specifications) {
  return specifications.map(specification => ({
    title: specification.split('\n\n', 1)[0].trim(),
    assertions: specification.match(/^( |\t)*(\|-)(.|\n)*?\./gm).map(assertion => {
      const assertionFragments = /(?:\|-) (\w*) ((?:.|\n)*)/.exec(assertion)
 
      return {
        value: assertionFragments[1],
        description: assertionFragments[2].replace(/\n /, '')
      }
    })
  }))
}
로그인 후 복사

这个函数将返回一个类似的数组,但是用一个如下结构的对象替换每个规范的内容:

title: <String: Name of this particular specification>,
  assertions: [
    {
      value: <Boolean: The result of the assertion>,
      description: <String: The short description for the assertion>
    }
  ]
}
로그인 후 복사

标题是用规范字符串的第一行设置的。然后,每个断言都作为数组存储在断言键中。该值将断言的结果表示为布尔值。我们将使用这个值来知道断言是否成功。

此外,描述将显示给用户,作为识别哪些断言成功和哪些断言失败的方法。我们在每种情况下都使用正则表达式。

记录结果

我们沿着程序构建的数组现在有一系列JavaScript规范文件,其中包含一列找到的断言及其结果和描述,因此除了向用户报告结果之外,没有什么可做的。

{
  function logAssertions(assertionGroups) {
  // Methods to log text with colors
  const ansiColor = {
    blue: text => console.log(`\x1b[1m\x1b[34m${text}\x1b[39m\x1b[22m`),
    green: text => console.log(`\x1b[32m    ${text}\x1b[39m`),
    red: text => console.log(`\x1b[31m    ${text}\x1b[39m`)
  }
  // Log the results
  assertionGroups.forEach(group => {
    ansiColor.blue(group.title)
    group.assertions.forEach(assertion => {
      assertion.value === &#39;true&#39;
        ? ansiColor.green(assertion.description)
        : ansiColor.red(assertion.description)
    })
  })
 
  console.log(&#39;\n&#39;)
}
로그인 후 복사

我们可以根据结果使用颜色来格式化输入。为了在终端上显示颜色,我们需要添加ANSI转义码。为了在下一个块中简化它们的用法,我们将每种颜色保存为ansiColor对象的方法。

首先,我们要显示规范的标题,请记住,我们为每个规范使用数组的第一个维度,并将其命名为一组(断言)。然后,我们使用它们各自的颜色根据它们的值记录所有断言:绿色表示计算为true的断言,红色表示具有其他值的断言。

注意比较,我们检查true是否为字符串,因为我们从每个文件接收字符串。

检查结果

最后,最后一步是检查所有测试是否成功。

function checkAssertions (assertionGroups) {
  return assertionGroups.some(
    group => group.assertions.some(assertion => assertion.value === &#39;false&#39;)
  ) ? 1 : 0
}
로그인 후 복사

我们使用数组的some()方法检查每个断言组(规范),看看是否至少有一个值是' ' ' false ' ' '。我们嵌套了其中的两个因为我们有一个二维数组。

运行我们的程序

此时,我们的CLI应准备好运行一些JavaScript规范,并查看是否拾取并评估了断言。在test目录中,您可以从本文开头复制规范示例,并将以下命令粘贴到您的文件中:package.json

"scripts": {
  "test": "node index.js test"
  }
로그인 후 복사

其中test是包含示例规范文件的目录的名称。

当运行npm test命令时,您应该看到使用它们各自颜色的结果。

相关免费学习推荐:js视频教程

更多编程相关知识,请访问:编程入门!!

위 내용은 실행 가능한 JavaScript 사양을 구축하는 방법에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:sitepoint.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿