So testen Sie Klassenkomponenten in Reaktion

9

Ich versuche einige Unit-Tests, ich habe eine Sandbox mit einem gefälschten Beispiel erstellt https://codesandbox.io/s/wizardly-hooks-32w6l (in Wirklichkeit habe ich ein Formular)

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;

Meine ursprüngliche Idee war es also, die Multiplikationsfunktion zu testen. Und das getan, was offensichtlich nicht funktioniert

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

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

Ich bekomme

_App.default.handleMultiply ist keine Funktion

Ist mein Ansatz richtig? Wenn ja, wie teste ich dann die Funktionen? Sonst sollte ich aus Anwendersicht statt auf interne Funktionen testen (das lese ich)? Sollte ich die Ausgabe auf dem Bildschirm testen (ich halte das nicht für sinnvoll)?

user3808307
quelle
2
Sie nähern sich dem mit der falschen Einstellung. Lösen Sie stattdessen das Senden des Formulars aus und überprüfen Sie, ob der Status einschließlich der Multiplikationslogik ordnungsgemäß aktualisiert wurde.
Alexander Staroselsky
@AlexanderStaroselsky ok, danke, ich werde versuchen, eine spezifischere Frage zu stellen, wenn ich nicht
weiterkomme
@AlexanderStaroselsky Was ist, wenn das Formular in einer untergeordneten Komponente und die Submit-Handler im übergeordneten Element? Muss ich dort Integrationstests durchführen?
user3808307
1
Es mag Ansichtssache sein, aber ich würde diese definitiv separat testen. Die Tests für das Kind wären, dass es beim Senden die vom Elternteil über Requisiten übergebene Funktion auslöst und dann auch testet, ob der Status wie erwartet gerendert wird. Für das übergeordnete Element würde ich das Ereignis auslösen und sicherstellen, dass der Status korrekt aktualisiert wurde.
Alexander Staroselsky
@AlexanderStaroselsky Vielen Dank
user3808307

Antworten:

4

Sie können die instance () -Methode von verwenden enzyme, um die Instanz von React Component abzurufen. Rufen Sie dann die handleMultiplyMethode direkt auf und machen Sie die Zusicherung dafür. Wenn die handleMultiplyMethode einen Nebeneffekt oder sehr komplizierte Berechnungen hat, müssen Sie einen einfachen verspotteten Rückgabewert dafür erstellen. Es wird eine isolierte Testumgebung für die handleSubmitMethode erstellt. Dies bedeutet, dass die handleSubmitMethode nicht vom Rückgabewert der tatsächlichen Implementierung der handleMultiplyMethode abhängt .

Z.B

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);
    });
  });
});

Unit-Testergebnisse mit Abdeckungsbericht:

 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

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

Slideshowp2
quelle
Was ist, wenn sich das Formular in einer untergeordneten Komponente befindet? Wie würde ich handleSubmit im Test auslösen, außer mit einem Formular senden? Vielen Dank
user3808307