Descripción general de las pruebas automatizadas de front-end [introducción súper completa]

inserte la descripción de la imagen aquí

¿Por qué necesita pruebas automatizadas?

Después de un desarrollo continuo, el proyecto eventualmente se volverá estable.La introducción de pruebas automatizadas en el momento apropiado puede detectar problemas temprano y garantizar la calidad del producto.
Beneficios de la automatización = número de iteraciones * costo de ejecución manual completa - costo de la primera automatización - número de mantenimiento * costo de mantenimiento

prueba

Como último eslabón en el proceso completo de desarrollo, las pruebas son un eslabón importante para garantizar la calidad del producto. Las pruebas de front-end son generalmente un eslabón tardío en el proceso de desarrollo del producto y pertenecen a un nivel superior en toda la arquitectura de desarrollo. Las pruebas de front-end están más inclinadas a las características de la GUI, por lo que las pruebas de front-end son muy difíciles.

método de prueba

pruebas de caja negra

Las pruebas de caja negra también se conocen comúnmente como pruebas funcionales. Las pruebas de caja negra requieren que el probador trate el programa como un todo, independientemente de su estructura y características internas, pero para verificar que el programa funciona como se espera. Las pruebas de caja negra están más cerca del escenario del mundo real que usa el usuario, porque las partes internas del programa son invisibles para el usuario.
Los siguientes son métodos de prueba comúnmente utilizados en las pruebas de caja negra:

División de Clase de Equivalencia

La división de clase de equivalencia es principalmente para determinar el intervalo de entrada legal e ilegal para diseñar casos de prueba bajo la condición de las reglas de entrada existentes.
Por ejemplo: por ejemplo, la contraseña de inicio de sesión del sitio web debe estar compuesta por 6 dígitos.
Clase de equivalencia válida: 6- Clase de equivalencia no válida de dígitos
: dígitos> 6, dígitos <6, números de ancho completo, letras, caracteres especiales, etc.

Análisis de valor límite

Como su nombre lo indica, el diseño de casos de prueba se basa principalmente en los valores límite de los rangos de entrada y salida. La razón es que a menudo se produce una gran cantidad de errores en los límites del rango de entrada o salida (los programadores tienden a cometer errores en estos lugares), y el análisis de valor límite generalmente se usa junto con la división de clases de equivalencia y el límite de equivalencia. el intervalo de división de clases es generalmente el valor límite.

Por ejemplo: la longitud de la contraseña de inicio de sesión del sitio web debe ser de 6 a 12 dígitos
Clase de equivalencia válida: dígitos [6-12]
Clase de equivalencia no válida: dígitos <6 dígitos> 12
Valor límite: 6 12

Especulación de errores, análisis de excepciones, etc.

Las pruebas de caja negra también incluyen algunos otros métodos de prueba.Dado que las pruebas a menudo son inagotables, cómo diseñar casos de prueba para garantizar que las pruebas cubran tantos escenarios como sea posible no solo se basan en estos métodos resumidos, sino también en el propio talento de los probadores.

pruebas de caja blanca

La prueba de caja blanca es una prueba basada en el propio código, generalmente refiriéndose a la prueba de la estructura lógica del código. La prueba de caja blanca es una prueba que se lleva a cabo bajo la premisa de comprender la estructura del código, y el propósito es atravesar tantas rutas ejecutables como sea posible para obtener datos de prueba. Existen muchos métodos de prueba de caja blanca, principalmente de cobertura lógica, es decir, verificando cada línea de código y cada resultado de juicio.
Los métodos de cobertura lógica se ordenan a partir de la capacidad de encontrar errores principalmente en las siguientes categorías:

Cobertura de declaraciones (permitir que el programa ejecute cada línea de declaraciones)
cobertura de decisiones (dejar que cada declaración de juicio satisfaga verdadero o falso)
cobertura de condición (dejar que cada condición en cada declaración de juicio tome el valor verdadero o falso)
cobertura de decisión/condición (satisfacer ambos 2 y 3)
Cobertura de combinación de condiciones (cada combinación de condiciones en la declaración de juicio aparece al menos una vez)
Cobertura de ruta (cubre cada ruta de ejecución del programa)

Clasificación de prueba

De acuerdo con el concepto ascendente de la ingeniería de software, las pruebas de front-end generalmente se dividen en pruebas unitarias (Pruebas unitarias), pruebas de integración (Pruebas de integración) y pruebas de extremo a extremo (Pruebas E2E). Como se puede ver en la figura a continuación, la complejidad de las pruebas ascendentes seguirá aumentando y, por otro lado, los beneficios de las pruebas seguirán disminuyendo.
inserte la descripción de la imagen aquí

Modelo de prueba de front-end

Examen de la unidad

La prueba unitaria se refiere a la prueba de la unidad más pequeña comprobable en un programa y generalmente se refiere a la prueba de funciones. Las pruebas unitarias mezclan la programación y las pruebas. Debido a que prueban la lógica interna del código, utilizan más métodos de prueba de caja blanca. Las pruebas unitarias obligan a los desarrolladores a escribir más código comprobable, que generalmente es mucho más legible, y las buenas pruebas unitarias sirven como documentación para el código bajo prueba.

Capacidad de prueba de funciones: las funciones con alta capacidad de prueba son generalmente funciones puras, es decir, funciones con entrada y salida predecibles. Es decir, los parámetros entrantes no se modifican dentro de la función, las solicitudes API o las solicitudes IO no se ejecutan y otras funciones impuras como Math.random() no se llaman.

La característica más importante de las pruebas unitarias es la granularidad fina del objeto de prueba, es decir, el objeto de prueba es muy independiente y de baja complejidad.

Pruebas unitarias de front-end

La mayor diferencia entre las pruebas de unidades de front-end y las pruebas de unidades de back-end es que los problemas de compatibilidad no se pueden evitar en las pruebas de unidades de front-end, como llamar a las API de compatibilidad del navegador y llamar a las API de BOM (Browser Object Model), por lo que la unidad de front-end testing Requiere ejecutarse en un (pseudo) entorno de navegador.
En lo que respecta a la clasificación del entorno operativo de prueba, existen principalmente los siguientes esquemas de prueba:

Basado en JSDOM

Ventajas: rápido, la velocidad de ejecución más rápida, porque no se
requiere iniciar el navegador Y JSDOM no implementa localStorage.Si necesita anularlo, solo puede usar una biblioteca de terceros como node-localStorage (esta biblioteca en sí tiene algunos problemas con el juicio del entorno de ejecución).

Basado en navegadores sin cabeza como PhantomJs

Ventajas: relativamente rápido y tiene un entorno DOM real
Desventajas: tampoco se ejecuta en un navegador real, es difícil de depurar y hay muchos problemas en el proyecto Después del lanzamiento de titiritero, el autor anunció que ya no ser mantenido

Use herramientas como Karma o titiritero para llamar al entorno real del navegador para realizar pruebas

Ventajas: configuración simple, puede ejecutar pruebas en navegadores reales y karma puede ejecutar código de prueba en múltiples navegadores, y al mismo tiempo facilitar la depuración
Desventajas: la única desventaja es que funciona un poco más lento que los dos primeros, pero en pruebas unitarias dentro rango aceptable

Herramientas de prueba de unidad de front-end

Una gran cantidad de marcos de prueba y herramientas relacionadas han surgido como hongos en el front-end en los últimos años.

plataforma de prueba

karma: una plataforma de ejecución de pruebas desarrollada por el equipo de Google Angular. Es simple y flexible de configurar y puede ejecutar fácilmente pruebas en múltiples navegadores reales.

marco de prueba

mocha: un excelente marco de prueba desarrollado por Tj, con un ecosistema completo, una organización de prueba simple, sin restricciones en las bibliotecas y herramientas de aserción, y muy flexible.
jasmine: muy similar a la sintaxis de Mocha, la mayor diferencia es que proporciona afirmaciones autoconstruidas y Spy and Stub
jest: un marco de prueba grande y completo producido por facebook, el marco de prueba de unidad recomendado oficialmente por React, con una configuración simple y un funcionamiento rápido. velocidad. (Nota: no se puede integrar con Karma)
AVA: la mayor diferencia con el marco de prueba anterior es que tiene varios subprocesos y se ejecuta más rápido.
Otros: existen algunos otros marcos de prueba de front-end, pero la similitud es relativamente alta. No es más que una diferencia en la integración de herramientas como aserciones y pilas de prueba. Si considera la estabilidad y la madurez, se recomienda elegir Mocha, que tiene requisitos muy altos para la prueba de velocidad de ejecución. Considere broma y AVA

ayudas de prueba

Biblioteca de aserciones: Chai Si la prueba unitaria no se ejecuta en el entorno real del navegador, simplemente puede usar la aserción del nodo, pero se recomienda usar Chai como la biblioteca de aserciones (proporciona una variedad de métodos de aserciones en los estilos TDD y BDD, y el el ecosistema es próspero).
Talones de prueba (también conocidos como dobles de prueba): Sinon, testDouble y otras herramientas proporcionan funciones como talones de prueba, interceptar solicitudes simuladas y "viajes en el tiempo", que se utilizan principalmente para resolver "funciones impuras" (como probar si la devolución de llamada se llama correctamente, si el XHR inicia correctamente la solicitud y si la función se comporta correctamente después del retraso de tiempo es el problema de prueba.

Herramienta de cobertura de prueba

estambul La implementación básica de estambul proporciona herramientas como la línea de comandos, pero no puede resolver el problema de la compilación y administración
de código.

otras referencias

chai-as-promise Amplía la función de aserción de Chai en Promise
sinon-chai Amplía la función de aserción de Chai cuando se combina con Sinon
chai-jquery Amplía la aserción de Chai en las pruebas de interfaz de usuario
El sitio web oficial de Estambul presenta cómo se integra Estambul con marcos de pruebas múltiples y para soporte de mecanografiado para otros idiomas
​​Ruan Yifeng - Herramienta de cobertura de código El tutorial de introducción de Estambul presenta los conceptos relacionados con la cobertura de código y el uso simple de Estambul con Mocha

Castañas de prueba de unidad común

Considere las siguientes condiciones o problemas al seleccionar un marco:

La prueba debe ejecutarse en un navegador real. La
ejecución de la prueba debe ser lo suficientemente rápida
. El código bajo prueba es Typescript, por lo que el uso debe resolver el problema de compilación y administración. Es
conveniente para la integración continua .

Finalmente, elija la solución usando Karma+Webpack+Mocha+Chai+Sion+istanbul-instrumenter-loader.
Estructura del proyecto:
inserte la descripción de la imagen aquí

Karma se puede integrar fácilmente con Webpack, solo necesita especificar los archivos que deben precompilarse y la herramienta de compilación que se utilizará.

karma.conf.js配置Webpack编译
module.export=funciton(config){
config.set({
    frameworks: ['mocha', 'chai'],
    files: [
  		'tests/setup.js'
	],
    preprocessors: {
      'tests/setup.js': ['webpack']
    },
    webpack: {
      resolve: {
        extensions: ['.js','.ts'],
      },
      module: {
        rules: [{
            test: /\.ts$/,
            loader: 'ts-loader',
            query: {
              transpileOnly: true
            }
          },
          {
            test: /\.ts$/,
            exclude: /(node_modules|libs|\.test\.ts$)/,
            loader: 'istanbul-instrumenter-loader',
            enforce: 'post',
            options: {
              esModules: true,
              produceSourceMap: true
            }
          }
        ]
      },
      devtool: 'inline-source-map',
    },
    // karma-server support ts/tsx mime 
    mime: {
      'text/x-typescript': ['ts', 'tsx']
    },
})

}

Hay algunas cosas a las que prestar atención en la configuración anterior:

configuración.js

        // 导入所有测试用例
const testsContext = require.context("../src", true, /\.test\.ts$/);
testsContext.keys().forEach(testsContext);

Use require.context() proporcionado por webpack para importar todos los archivos de prueba de manera uniforme, luego karma usa setup.js como la entrada para llamar a webpack para compilar, y luego se ejecuta la prueba.

soporte de configuración mime para ts/tsx

El orden en el que se llama al cargador istanbul-instrumenter-loader debe compilarse antes de compilar ts o babel y otras herramientas de compilación; de lo contrario, será inexacto, excluyendo el archivo de prueba en sí y el cálculo de cobertura de la biblioteca de dependencias.

 使用enforce: ‘post’,确保loader调用顺序
 使用exclude排除第三方库和测试文件本身覆盖率计算

Para otras configuraciones, consulte karma y webpack, así como la documentación del complemento relacionado

prueba de función pura

            /**
 * 验证邮箱
 * @params input 输入值
 * @return 返回是否是邮箱
 */
export function mail(input: any): boolean {
    return /^[\w\-]+(\.[\w\-]+)*@[\w\-]+(\.[\w\-]+)+$/.test(input);
}

/* ↑↑↑↑被测函数↑↑↑↑ */
/* ↓↓↓↓测试代码↓↓↓↓ */

describe('验证邮箱#mail', () => {
    it('传入邮箱字符串,返回true', () => {
        expect(mail('[email protected]')).to.be.true;
        expect(mail('[email protected]')).to.be.true;
        expect(mail('[email protected]')).to.be.true;
        expect(mail('[email protected]')).to.be.true;
        expect(mail('[email protected]')).to.be.true;
    });

    it('传入非邮箱字符串,返回true', () => {
        expect(mail('')).to.be.false;
        expect(mail('abc@')).to.be.false;
        expect(mail('@123.com')).to.be.false;
        expect(mail('abc@123')).to.be.false;
        expect(mail('123.com')).to.be.false;
    });
});

Promesa u otras pruebas de operación asíncrona
Mocha admite pruebas asíncronas, principalmente de las siguientes tres maneras:

espera asíncrona

                it(async ()=>{
await asynchronous()
// 一些断言

})

Usar la función de devolución de llamada

                it(done=>{
Promise.resolve().then(()=>{
    // 断言
    done() // 测试结束后调用回调标识测试结束
})

})

devolver una promesa

                it(()=>{
// 直接返回一个Promise,Mocha会自动等待Promise resolve
return Promise.resolve().then(()=>{
    // 断言
})

})

Prueba con solicitud HTTP

            function http(method,url,body){
    // 使用XHR发送ajax请求
}

/* ↑↑↑↑被测函数↑↑↑↑ */
/* ↓↓↓↓测试代码↓↓↓↓ */

it('method为GET', (done) => {
    const xhr=fake.useFakeXMLHttpRequest()
    const request = []
    xhr.onCreate = xhr => {
        requests.push(xhr);
    };
    requests[0].respond(200, { "Content-Type": "application/json" },'[{ "id": 12, "comment": "Hey there" }]');
    get('/uri').then(() => {
            xhr.restore();
            done();
    });
    expect(request[0].method).equal('GET');
})

O encapsular fakeXMLHttpRequest

            /**
 * 使用fakeXMLHttpRequest
 * @param callback 回调函数,接受请求对象作为参数
 */
export function useFakeXHR(callback) {
    const fakeXHR = useFakeXMLHttpRequest();
    const requests: Array<any> = []; // requests会将引用传递给callback,因此使用const,避免指针被改写。

    fakeXHR.onCreate = request => requests.push(request);

    callback(requests, fakeXHR.restore.bind(fakeXHR));
}

it('method为GET', (done) => {
    useFakeXHR((request, restore) => {
        get('/uri').then(() => {
            restore();
            done();
        });
        expect(request[0].method).equal('GET');
        request[0].respond();
    })
})

useFakeXHR encapsula useFakeXMLHttpRequest de Sinon para implementar solicitudes XHR falsas

Fake XHR and server - Sinon.JS 官方文档参考
Fake XHR和 Fake server的区别:后者是对前者的更高层次的封装,并且Fake server的颗粒度更大

pruebas dependientes del tiempo

        // 延迟delay毫秒后调用callback
function timer(delay,callback){
    setTimeout(callback,delay);
}

/* ↑↑↑↑被测函数↑↑↑↑ */
/* ↓↓↓↓测试代码↓↓↓↓ */

it('timer',()=>{
    const clock=sinon.useFakeTimers()
    const spy=sinon.spy() // 测试替身
    timer(1000,spy) 
    clock.tick(1000) // "时间旅行,去到1000ms后"
    expect(spy.called).to.be.true
    clock.restore() // 恢复时间,否则将影响到其他测试
})

Prueba de llamadas API relacionadas con el navegador

sesión castaña

            /**
 * WebStorage封装
 * @param storage 存储对象,支持localStorage和sessionStorage
 * @return 返回封装的存储接口
 */
export function Storage(storage: Storage) {
    /**
     * 获取session
     * @param key 
     * @return 返回JSON解析后的值
     */
    function get(key: string) {
        const item = storage.getItem(key);

        if (!item) {
            return null;
        } else {
            return JSON.parse(item);
        }
    }
}
export default Storage(window.sessionStorage);

/* ↑↑↑↑被测函数↑↑↑↑ */
/* ↓↓↓↓测试代码↓↓↓↓ */

describe('session', () => {
    beforeEach('清空sessionStorage', () => {
        window.sessionStorage.clear();
    });

    describe('获取session#get', () => {
        it('获取简单类型值', () => {
            window.sessionStorage.setItem('foo', JSON.stringify('foo'))
            expect(session.get('foo')).to.equal('foo');
        });

        it('获取引用类型值', () => {
            window.sessionStorage.setItem('object', JSON.stringify({}))
            expect(session.get('object')).to.deep.equal({});
        });

        it('获取不存在的session', () => {
            expect(session.get('aaa')).to.be.null;
        });
    });
})

Establecer la castaña del título.

            /**
 * 设置tab页title
 * @param title 
 */
export function setTitle(title) {
    // 当页面中嵌入了flash,并且页面的地址中含有“片段标识”(即网址#之后的文字)IE标签页标题被自动修改为网址片段标识
    if (userAgent().app === Browser.MSIE || userAgent().app === Browser.Edge) {
        setTimeout(function () {
            document.title = title
        }, 1000)
    } else {
        document.title = title
    }
}

/* ↑↑↑↑被测函数↑↑↑↑ */
/* ↓↓↓↓测试代码↓↓↓↓ */

it('设置tab页title#setTitle', () => {
    // 这个测试不是个好的测试,测试代码更改了页面DOM结构
    const originalTitle = document.title; // 保存原始title,测试结束后恢复
    const clock = sinon.useFakeTimers()
    setTitle('test title');
    clock.tick(1000)
    expect(document.title).to.equal('test title')

    setTitle(originalTitle); // 恢复原本的title
    clock.tick(1000)
    clock.restore()
})

Pruebas unitarias de componentes de reacción

La prueba de los componentes React no es muy diferente de otras pruebas unitarias en esencia, pero la prueba unitaria de los componentes React es mucho más compleja debido al problema de "representación del navegador" involucrado, y los componentes React se suman a los componentes básicos de la interfaz de usuario (como Button, Link), etc. Fuera de los componentes subyacentes, en realidad es difícil mantener su "escala" dentro del rango de "unidad de prueba mínima", aunque la complejidad del componente se puede reducir mediante una "representación superficial" (sin representación de subcomponentes). Desde la perspectiva del alcance y la importancia de las pruebas unitarias, de hecho, la mayoría de las pruebas de componentes de la interfaz de usuario son difíciles de clasificar en pruebas unitarias. Dado que "todo el mundo parece darlo por sentado", este documento aún presenta las pruebas de componentes de la interfaz de usuario como pruebas unitarias.

        没有打开盒子时,我们无法决定猫是否还活着。

React no es una caja negra, por lo que para probar React, primero debe comprender cómo se procesa React. Por supuesto, no necesitamos entender el código fuente de React, solo conocerlo.
En pocas palabras, se necesitan los siguientes pasos para convertir un componente de React en una página.

  1. Calcule el objeto DOM virtual en función del estado

  2. Generar estructura de Dom real basada en DOM virtual

  3. Monte Dom a la página

    Pero en la prueba, no necesitamos montar el componente en la página, solo tener un entorno Dom. Si no necesita un componente de renderizado completo, incluso puede no tener un entorno Dom.

    Enzima

    Enzyme (enzima, catalizador) es una herramienta de prueba de React proporcionada por Airbnb. Proporciona Renderizado superficial | Renderizado completo | Renderizado estático para probar los componentes de React. Prueba con renderizado superficial.

     使用Enzyme进行测试前需要先初始化React适配器,具体配置请查看官方手册
    

Representación superficial

Solo se renderiza la estructura exterior del componente y los subcomponentes no se renderizan
Un ejemplo de una prueba completa de renderizado superficial:

            import * as React from 'react'
import * as classnames from 'classnames'
import { ClassName } from '../helper'
import * as styles from './styles.desktop.css'

const AppBar: React.StatelessComponent<any> = function AppBar({ className, children, ...props } = {}) {
    return (
        <div className={classnames(styles['app-bar'], ClassName.BorderTopColor, className)} {...props}>{children}</div>
    )
}


export default AppBar

            import * as React from 'react';
import { shallow } from 'enzyme';
import { expect } from 'chai';
import AppBar from '../ui.desktop'

describe('ShareWebUI', () => {
    describe('AppBar@desktop', () => {
        describe('#render', () => {
            it('默认渲染', () => {
                shallow(<AppBar></AppBar>) 
            });
            it('正确渲染子节点', () => {
                const wrapper = shallow(<AppBar><div>test</div></AppBar>)
                expect(wrapper.contains(<div>test</div>)).to.be.true
            });
            it('允许设置ClassName', () => {
                const wrapper = shallow(<AppBar className='test'></AppBar>)
                expect(wrapper.hasClass('test')).to.be.true
            });
            it('允许设置其他自定义props', () => {
                const wrapper = shallow(<AppBar name='name' age={123}></AppBar>)
                expect(wrapper.props()).to.be.include({ name: 'name', age: 123 })
            });
        });
    });
});

La representación completa representa
la estructura real del componente Dom. Si necesita probar eventos nativos, debe utilizar este método de representación.

El renderizado estático
es similar al resultado obtenido por el rastreador, obteniendo la cadena HTML de la página y usando Cheerio para operar.

La simulación de eventos en el modo de renderizado superficial de Enzyme no es una activación de evento real. De hecho, es una implementación de "engaño". Por ejemplo, buttonWrapper.simulate('click') simplemente llama a la función pasada al parámetro onClick del componente Button Eso es todo.
Descripción específica: airbnb.io/enzyme/docs...
Los muchos hoyos de Enzyme: airbnb.io/enzyme/docs...
Si se llama a setState() en una operación asincrónica, la prueba debe afirmarse en el siguiente ciclo de reloj ( problemas similares son más muchos):

/* Simula un clic /
wrapper.find('UIIcon').simulate('click')
expect(wrapper.state('loadStatus')).to.equal(1) // Haz clic para cambiar inmediatamente el estado de carga a loading
/
en SetState se establece en promise.then, por lo que debe afirmarse en el siguiente reloj */
setTimeout(() => { expect(wrapper.state('loadStatus')).to.equal(2) done() }, 0)


Pruebas de integración

La prueba de integración se refiere a la encapsulación de funciones o clases de alto nivel expuestas mediante la combinación e integración de las funciones de prueba unitaria probadas sobre la base de la prueba unitaria y la prueba de estas funciones o clases.
La mayor dificultad en las pruebas de integración es que la granularidad es mayor, la lógica es más compleja y hay más factores externos que no pueden garantizar la controlabilidad y la independencia de la prueba. La solución es usar stubs de prueba (test doubles), es decir, reemplazar la subfunción o módulo que se llama, es decir, ocultar los detalles del submódulo y controlar el comportamiento del submódulo para lograr la prueba esperada. (La premisa aquí es que el submódulo ha sido cubierto por pruebas unitarias completas, por lo que se puede suponer que se conoce el estado del submódulo).

Typescript compila a Commonjs:

    // 编译前
import * as B from 'B'
import {fn} from 'C'

export function A() { 
    B.fn.name()
    fn.name()
}

export class A1 {
    
}

// 编译后
define(["require", "exports", "B", "C"], function (require, exports, B, C_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    function A() {
        B.fn.name();
        C_1.fn.name();
    }
    exports.A = A;
    var A1 = /** @class */ (function () {
        function A1() {
        }
        return A1;
    }());
    exports.A1 = A1;
});

Todas las funciones y clases exportadas están bajo el objeto de exportaciones. Dado que la llamada en realidad se llama exportaciones.exportName, si desea Stub, necesita las propiedades en Exportaciones de Stub. La función de stub proporcionada por Sinon nos permite modificar cualquier objeto bajo un objeto. Atributo, tenga en cuenta que debe estar debajo de un objeto, es decir, no puede ser directamente sinon.stub(fn), solo sinon.stub(obj,'fnName'). En ES6, puede exportar todo el módulo a un solo objeto a través de import * as moduleName from 'moduleName', lo que puede resolver el problema de Stub.
Considere tener las siguientes dependencias de módulo:
inserte la descripción de la imagen aquí

Entre ellos, el módulo A depende de los módulos B y C, y el módulo B depende del módulo C. En este caso, podemos elegir solo el módulo Stub C. En este momento, el módulo C en el módulo B también se verá afectado por Stub. la mejor manera es simultáneamente el módulo Stub B y el módulo C.
castaña

    import { clientAPI } from '../../../clientapi/clientapi';

/**
 * 通过相对路径获取缓存信息
 * @param param0 参数对象
 * @param param0.relPath 相对路径
 */
export const getInfoByPath: Core.APIs.Client.Cache.GetInfoByPath = function ({ relPath }) {
    return clientAPI('cache', 'GetInfoByPath', { relPath });
}

/* ↑↑↑↑被测函数↑↑↑↑ */
/* ↓↓↓↓测试代码↓↓↓↓ */

import { expect } from 'chai'
import { stub } from 'sinon'
import * as clientapi from '../../../clientapi/clientapi';

import { getInfoByPath, getUnsyncLog, getUnsyncLogNum } from './cache'

describe('cache', () => {
    beforeEach('stub', () => {
        stub(clientapi, 'clientAPI')
    })
    afterEach('restore', () => {
        clientapi.clientAPI.restore()
    })

    it('通过相对路径获取缓存信息#getInfoByPath', () => {
        getInfoByPath({ relPath: 'relPath' })
        expect(clientapi.clientAPI.args[0][0]).to.equal('cache') // 请求资源正确
        expect(clientapi.clientAPI.args[0][1]).to.equal('GetInfoByPath') // 请求方法正确
        expect(clientapi.clientAPI.args[0][2]).to.deep.equal({ relPath: 'relPath' }) // 请求体正确
    })
})

O use Sandbox proporcionado por Sinon, que es más fácil de restaurar y no necesita restaurar cada objeto stub por separado.

import { rsaEncrypt } from '../../util/rsa/rsa';
import { getNew} from '../apis/eachttp/auth1/auth1';
/**
 * 认证用户
 * @param account {string}
 * @param password {string}
 */
export function auth(account: string, password: string, ostype: number, vcodeinfo?: Core.APIs.EACHTTP.Auth1.VcodeInfo): Promise<Core.APIs.EACHTTP.AuthInfo> {
    return getNew({
        account,
        password: encrypt(password),
        deviceinfo: {
            ostype: ostype
        },
        vcodeinfo
    });
}

/* ↑↑↑↑被测函数↑↑↑↑ */
/* ↓↓↓↓测试代码↓↓↓↓ */
import { createSandbox } from 'sinon'
import * as auth1 from '../apis/eachttp/auth1/auth1'
import * as rsa from '../../util/rsa/rsa'
const sandbox = createSandbox()
describe('auth', () => {
    beforeEach('stub',()=>{
        sandbox.stub(rsa,'rsaEncrypt')
        sandbox.stub(auth1,'getNew')
    })
    
    afterEach('restore',()=>{
        sandbox.restore()
    })
    
    it('认证用户#auth', () => {
        auth('account', 'password', 1, { uuid: '12140661-e35b-4551-84cf-ce0e513d1596', vcode: '1abc', ismodif: false })
        rsa.rsaEncrypt.returns('123') // 控制返回值
		expect(rsa.rsaEncrypt.calledWith('password')).to.be.true
        expect(auth1.getNew.calledWith({
            account: 'account',
            password: '123',
            deviceinfo: {
                ostype: 1
            },
            vcodeinfo: {
                uuid: '12140661-e35b-4551-84cf-ce0e513d1596',
                vcode: '1abc',
                ismodif: false
            }
        })).to.be.true
    })
}

Documentación de referencia:

        Stubs - Sinon.JS Stub的相关概念和使用
        Sandboxes - Sinon.JS Sandbox(沙盒)的相关概念和使用

Prueba de extremo a extremo (Prueba E2E) La prueba
de extremo a extremo es la prueba de nivel superior, es decir, trata el programa como una caja negra completa como usuario, abre la aplicación para simular la entrada y verifica si la función y la interfaz son correctas.
Algunos problemas que deben abordarse para las pruebas de extremo a extremo:

El problema del entorno
es cómo garantizar que el entorno antes de cada prueba esté "limpio". Por ejemplo, es necesario verificar el rendimiento de la lista vacía. Si la lista se agregó en la prueba anterior, la próxima prueba no podrá para obtener el estado de la lista vacía.
La solución más fácil es llamar a un script externo para borrar la base de datos, etc. antes o después de que se ejecuten todas las pruebas, o puede resolverse interceptando la solicitud y personalizando la respuesta (esto conducirá a una alta complejidad de la prueba y no suficiente "realidad"). " ).

Búsqueda de elementos
Si el código cambia con frecuencia, la estructura del componente cambia con frecuencia, y si busca el elemento de acción basado en la estructura DOM, caerá en el infierno de mantener selectores. La mejor práctica es usar el método de identificación de prueba, pero este método requiere la cooperación de desarrolladores y evaluadores para definir identificaciones de prueba semánticas en elementos procesables.

La espera de operación
, como los cambios de interfaz causados ​​por solicitudes de red asíncronas o animaciones de interfaz, harán que se desconozca el tiempo de obtención de los elementos de operación. La solución es esperar hasta que se complete la solicitud de escucha y se obtenga correctamente el elemento deseado.

Use operaciones en lugar de aserciones
Debe confiar más en las operaciones que en las aserciones. Por ejemplo, si una operación depende de la existencia del elemento A, no necesita "juzgar si el elemento A existe en la página", sino que debe ir a "obtener directamente el elemento A y operar", porque si el elemento A no existe , definitivamente no se obtendrá. , la operación posterior a la afirmación no tendrá sentido, por lo que puede usar la operación directamente en lugar de la función de espera de afirmación.

Finalmente: [Puede ayudarte]

Estos materiales deben ser el almacén de preparación más amplio y completo para los amigos que están considerando habilidades avanzadas [de prueba de software] Este almacén también me ha acompañado a través del viaje más difícil, y espero que también pueda ayudarlos.
inserte la descripción de la imagen aquí

Siga mi cuenta pública de WeChat [Programa Yuanmuzi] para obtenerlo gratis

Mi grupo de intercambio de aprendizaje: 644956177 Hay expertos técnicos en el grupo para comunicarse y compartir ~

Supongo que te gusta

Origin blog.csdn.net/Xsk215/article/details/117160879
Recomendado
Clasificación