简体   繁体   中英

Can I do all my unit-tests with only shallow rendering and without mounting the full component tree?

Please let me illustrate. Let's say we have this to do app:

// TodoContainer.jsx
<TodoContainer>
  <AddTodo />
  <TodoList />
</TodoContainer>

My question is how should I test its add todo functionality? Is it enough to..

Approach #1

  1. shallow render TodoContainer and assert that..

    a. it has a working addTodoMethod which updates the state accordingly

    b. it passes the addTodoMethod its child composite component, AddTodo

  2. shallow render AddTodo and assert that..

    a. it has received the addTodoMethod as prop

    b. it fires the addTodoMethod on button click

This is how approach #1 would look like:

// TodoContainer.spec.jsx
describe('<TodoContainer />', function()  {
  describe('addTodoMethod', function()  {
    beforeEach(function() {
      this.todoContainer = shallow(<TodoContainer />)
    })

    it('adds todo to todos state when called', function() {
      const todos = this.todoContainer.instance().state('todos')

      this.todoContainer.instance().addToDoMethod('sample todo item')

      expect(todos).length.to.be(1)
      expect(todos[0]).to.be('sample to do item')
    })

    it('is passed do AddTodo component', function()  {
      const addTodo = shallow(<AddTodo />)

      expect(addTodo.instance().prop('onClick')).to.eql.(this.todoContainer.addTodoMethod)
    })
  })
})

// TodoContainer.spec.jsx
describe('<AddTodo />', function()  {
  beforeEach(function() {
    this.addTodo = shallow(<AddTodo />)
  })

  it('has onClick prop', function() {
    expect(this.addTodo).to.be.a('function')
  })

  it('calls onClick when clicked', function()  {
    const onClickSpy = spy();
    const addTodo = shallow(<AddTodo onClick={onClickSpy} />)

    addTodo.setState({ newTodoText: 'sample new todo' })
    addButton.find('button').simulate('click');

    expect(onClickSpy.calledOnce()).to.be.true
    expect(onClickSpy.calledWith('sample new todo')).to.be.true
  })
})

or should I also do this next approach?

Approach #2

  1. in addition to assertions above , also mount the TodoContainer to assert that..

    a. it can add a todo item thru inputting new to do text and clicking button (both in AddTodo component), the new todo item is also asserted thru transversing to TodoList component and check if it has the correct number of li with their correct content.

Code for approach #2:

// TodoContainer.spec.jsx
describe('<TodoContainer />', function()  {
    ...

    it('can add a todo item', function() {
      this.todoContainer.find('input').simulate('change', {target: {value: 'sample new todo 01'}})
      this.todoContainer.find('button').simulate('click')

      expect(this.todoContainer).to.have.exactly(1).descendants('li')
      expect(this.todoContainer.find('li')[0]).to.have.text('sample new todo')

      this.todoContainer.find('input').simulate('change', {target: {value: 'sample new todo 02'}})
      this.todoContainer.find('button').simulate('click')

      expect(this.todoContainer).to.have.exactly(2).descendants('li')
      expect(this.todoContainer.find('li')[1]).to.have.text('sample new todo 02')
    })
})

I'm just thinking if the second approach is kinda redundant, and if it is a better practice to focus only on testing the component at hand and letting the child components rely on their own tests.

In short, yes - you can write all of your unit tests with shallow . And in most cases, you probably want exactly that. There are some times however when there's an exception where you'd want to use mount instead:

  1. If a certain group of components are clustered together, and you're more interested in testing the cluster as a whole instead of each part individually.
  2. If your component is tightly coupled to an external library, and testing your component individually would feel more like you're testing that external library.

As a general rule of thumb, though, I tend to reach for shallow for unit tests, mount for integration tests.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM