Come testare i componenti della classe in reagire


9

Sto provando alcuni test unitari, ho creato un sandbox con un esempio falso https://codesandbox.io/s/wizardly-hooks-32w6l (in realtà ho un modulo)

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { number: 0 };    
  }

  handleSubmit = (number1, number2) => {
    this.setState({ number: this.handleMultiply(number1, number2) })
  }

  handleMultiply = (number1, number2) => {
    return number1 * number2
  }

  render() {
    const { number } = this.state;

    return (
      <div className="App">
        <form onSubmit={e => this.handleSubmit(3, 7)}>       
          <input type="submit" name="Submit" value="Multiply" />
        </form>
        <Table number={number} />
      </div>
    );
  }
}

export default App;

Quindi la mia idea iniziale era di provare a testare la funzione moltiplica. E ha fatto questo, che ovviamente non funziona

import App from "../src/App";

test("Multiply", function() {
  const expected = 21;
  const result = App.handleMultiply(3, 7);
  expect(result).toBe(expected);
});

ottengo

_App.default.handleMultiply non è una funzione

Il mio approccio è giusto? Se sì, come testare le funzioni? Altrimenti, dovrei testare dal punto di vista dell'utente anziché per le funzioni interne (questo è quello che ho letto)? Devo testare l'output sullo schermo (non credo sia ragionevole)?


2
Ti stai avvicinando con la mentalità sbagliata. Attiva invece l'invio del modulo, quindi verifica che lo stato sia stato aggiornato in modo appropriato includendo la logica di moltiplicazione.
Alexander Staroselsky il

@AlexanderStaroselsky ok, grazie, proverò e farò una domanda più specifica se
rimango

@AlexanderStaroselsky cosa succede se il modulo in un componente figlio e i gestori di invio nel genitore? Devo fare dei test di integrazione lì?
user3808307,

1
Potrebbe essere una questione di opinione, ma sicuramente li testerei separatamente. Il test per il bambino sarebbe che al momento dell'invio innesca la funzione passata dal genitore tramite i puntelli, quindi anche per verificare che lo stato venga visualizzato come ti aspetteresti. Per il genitore, attiverei l'evento e mi assicurerei che lo stato sia stato aggiornato correttamente.
Alexander Staroselsky il

@AlexanderStaroselsky Grazie
user3808307

Risposte:


4

È possibile utilizzare il metodo instance () di enzymeper ottenere l'istanza di React Component. Quindi, chiama handleMultiplydirettamente il metodo e fai la sua affermazione. Inoltre, se il handleMultiplymetodo ha un effetto collaterale o calcoli molto complicati, è necessario creare un semplice valore restituito simulato. Creerà un ambiente di test isolato per il handleSubmitmetodo. Ciò significa che il handleSubmitmetodo non dipenderà dal valore di ritorno della reale implementazione del handleMultiplymetodo.

Per esempio

app.jsx:

import React from 'react';
import { Table } from './table';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { number: 0 };
  }

  handleSubmit = (number1, number2) => {
    this.setState({ number: this.handleMultiply(number1, number2) });
  };

  handleMultiply = (number1, number2) => {
    return number1 * number2;
  };

  render() {
    const { number } = this.state;

    return (
      <div className="App">
        <form onSubmit={(e) => this.handleSubmit(3, 7)}>
          <input type="submit" name="Submit" value="Multiply" />
        </form>
        <Table number={number} />
      </div>
    );
  }
}

export default App;

table.jsx:

import React from 'react';

export const Table = ({ number: num }) => {
  return <div>table: {num}</div>;
};

app.test.jsx:

import App from './app';
import { shallow } from 'enzyme';

describe('59796928', () => {
  let wrapper;
  beforeEach(() => {
    wrapper = shallow(<App></App>);
  });
  describe('#handleSubmit', () => {
    it('should pass', () => {
      expect(wrapper.exists()).toBeTruthy();
      wrapper.find('form').simulate('submit');
      expect(wrapper.state()).toEqual({ number: 21 });
    });
  });
  describe('#handleMultiply', () => {
    it('should pass', () => {
      const comp = wrapper.instance();
      const actual = comp.handleMultiply(2, 10);
      expect(actual).toBe(20);
    });
  });
});

Risultati del test unitario con rapporto di copertura:

 PASS  src/stackoverflow/59796928/app.test.jsx (11.688s)
  59796928
    #handleSubmit
       should pass (16ms)
    #handleMultiply
       should pass (9ms)

-----------|----------|----------|----------|----------|-------------------|
File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files  |    90.48 |      100 |    85.71 |    94.44 |                   |
 app.jsx   |      100 |      100 |      100 |      100 |                   |
 table.jsx |       50 |      100 |        0 |    66.67 |                 4 |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        13.936s

Codice sorgente: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59796928


E se il modulo fosse in un componente figlio? Come innescerei handleSubmit nel test, a parte quello con un modulo inviato? Grazie
user3808307
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.