原文摘自:https://dmitripavlutin.com/7-architectural-attributes-of-a-reliable-react-component/#6testableandtested
一個被驗證過針對給定的輸入會渲染出符合期望的輸出的元件,稱為 測試過的(tested) 元件;
一個 可測試的(testable) 元件意味著其易於測試
如何確保一個元件如期望的工作呢?你可以說:“我都自己手動試過的呀。”
如果你打算對每個元件的每個改動都手動驗證的話,或早或晚的,你就會跳過這項苦差事了,而小的瑕疵早晚也會出現。
這就是對元件的自動化驗證,也就是單元測試(unit test),為何重要的原因。單元測試保證了每次對元件做出的更改後,元件都能正確工作。
單元測試並不只與早期發現 bug 有關。另一個重要的方面是用其檢驗元件架構化水平優劣的能力。
我覺得這句話格外的重要:
一個 無法測試 或 難以測試 的元件,基本上就等同於 設計得很拙劣 的元件.
元件之所以難以測試時因為其有太多的 props、依賴、引用的模型和對全域性變數的訪問 -- 這都是不良設計的標誌。
一個架構設計羸弱的元件,就會變成無法測試的,進而你就會簡單的跳過單元測試,又導致了其保持未測試狀態,這是一個惡性迴圈。
總之,許多應用為何是未測試狀態的原因就是不良的元件設計。即便你想動手測試,也無處下手。
案例學習:可測試就意味著設計良好i
之前的文章中提及過 <Controls>
元件。
下面的程式碼測試了高度依賴於父元件結構的 <Controls>
版本:
import assert from 'assert';
import { shallow } from 'enzyme';
class Controls extends Component {
render() {
return (
<div className="controls">
<button onClick={() => this.updateNumber(+1)}>
Increase
</button>
<button onClick={() => this.updateNumber(-1)}>
Decrease
</button>
</div>
);
}
updateNumber(toAdd) {
this.props.parent.setState(prevState => ({
number: prevState.number + toAdd
}));
}
}
class Temp extends Component {
constructor(props) {
super(props);
this.state = { number: 0 };
}
render() {
return null;
}
}
describe('<Controls />', function() {
it('should update parent state', function() {
const parent = shallow(<Temp/>);
const wrapper = shallow(<Controls parent={parent} />);
assert(parent.state('number') === 0);
wrapper.find('button').at(0).simulate('click');
assert(parent.state('number') === 1);
wrapper.find('button').at(1).simulate('click');
assert(parent.state('number') === 0);
});
});
複製程式碼
<Controls>
測試起來非常複雜,因為它關聯了父元件的實現細節。
測試場景中需要一個額外的 <Temp>
元件,用來模擬父元件,檢驗 <Controls>
是否正確修改了父元件的狀態。
當 <Controls>
獨立於父元件的細節時,測試就簡單了。讓我們測試一下合理封裝版本的 <Controls>
元件:
import assert from 'assert';
import { shallow } from 'enzyme';
import { spy } from 'sinon';
function Controls({ onIncrease, onDecrease }) {
return (
<div className="controls">
<button onClick={onIncrease}>Increase</button>
<button onClick={onDecrease}>Decrease</button>
</div>
);
}
describe('<Controls />', function() {
it('should execute callback on buttons click', function() {
const increase = sinon.spy();
const descrease = sinon.spy();
const wrapper = shallow(
<Controls onIncrease={increase} onDecrease={descrease} />
);
wrapper.find('button').at(0).simulate('click');
assert(increase.calledOnce);
wrapper.find('button').at(1).simulate('click');
assert(descrease.calledOnce);
});
});
複製程式碼
封裝好則測試易,反之不恰當的封裝讓測試變得困難。
可測試性是一個檢驗元件結構良好程度的實踐標準。
轉載請註明出處
長按二維碼或搜尋 fewelife 關注我們哦