<p>In diesem Artikel erfahren Sie, wie Sie Jasmine für Angular-Unit-Tests verwenden. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein. </p>
<p><img src="https://img.php.cn/upload/article/000/000/024/5f408f91953d2985.jpg" alt="Einführung in Angular-Unit-Tests mit Jasmine" ></p>
<p>Das Folgende habe ich unter der Annahme erstellt, dass diejenigen, die selten oder gar keine Unit-Tests geschrieben haben, daher viele konzeptionelle Probleme in der Landessprache erklären können und sie auch in Kombination mit Jasmines entsprechenden Methoden erklären werden. </p>
<p><span style="font-size: 20px;"><strong> 1. Konzept </strong></span></p>
<p><span style="font-size: 18px;"><strong>Test Suite</strong></span></p>
<p>Test Suite, selbst eine einfache Klasse, wird mehrere Testfälle haben, daher wird die Sammlung dieser Testfälle unter einer Kategorie <strong>Test Suite</strong> genannt. </p>
<p>In Jasmine wird es durch die globale Funktion <code>describe</code> dargestellt. Der erste Zeichenfolgenparameter wird zur Darstellung des Namens oder Titels der Suite verwendet, und der zweite Methodenparameter dient zur Implementierung des Suite-Codes. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">describe('test suite name', () => {
});</pre><div class="contentsignin">Nach dem Login kopieren</div></div><p><span style="font-size: 18px;"><strong>Specs</strong></span></p><p>Eine Specs entspricht einem Testfall, also dem spezifischen Codekörper, den wir zum Testen implementieren. </p><p>Jasmine verwendet zur Darstellung die globale Funktion <code>it</code>, ähnlich wie <code>describe</code>, mit zwei Parametern: Zeichenfolge und Methode. </p><p>Jede Spezifikation enthält mehrere Erwartungen zum Testen des zu testenden Codes. Solange ein Erwartungsergebnis <code>false</code> ist, bedeutet dies, dass sich der Testfall in einem fehlgeschlagenen Zustand befindet. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">describe('demo test', () => {
const VALUE = true;
it('should be true', () => {
expect(VALUE).toBe(VALUE);
})
});</pre><div class="contentsignin">Nach dem Login kopieren</div></div><p><span style="font-size: 18px;"><strong>Erwartungen</strong></span></p><p>Behauptungen, die durch <code>expect</code> globale Funktionen dargestellt werden, erhalten nur einen Repräsentanten des zu testenden <strong>tatsächlichen Werts</strong> und müssen mit einem Matcher abgeglichen werden, der den <strong>Erwartungswert</strong> darstellt. </p><p><span style="font-size: 20px;"><strong> 2. Häufig verwendete Methoden</strong></span></p><p><span style="font-size: 18px;"><strong>Matchers</strong></span></p><p>Übereinstimmungsvorgänge durchführen, zwischen tatsächlichen Werten und erwarteten Werten vergleichen und Jasmine über die Ergebnisse benachrichtigen. Schließlich bestimmt Jasmine, ob diese Spezifikation erfolgreich ist oder scheitert. </p><p>Jasmine bietet eine sehr umfangreiche API, einige häufig verwendete Matcher: </p><ul><li><code>toBe()</code> entspricht <code>===</code></li><li>toNotBe() entspricht <code>!==</code></li><li>toBeDefined() entspricht <code>!== undefined</code></li><li>toBeUndefined() entspricht <code>=== undefined</code></li> <li>toBeNull() Das Gleiche wie <code>=== null</code></li><li> toBeTruthy() entspricht <code>!!obj</code></li><li> toBeFalsy() entspricht <code>!obj</code></li><li> toBeLessThan() entspricht <code><</code></li><li>toBeGreaterThan() entspricht <code>></code></li><li>toEqual() Äquivalent to <code>==</code></li><li>toNotEqual() ist äquivalent zu <code>!=</code></li> <li>toContain() ist äquivalent zu <code>indexOf</code> </li><li>toBeCloseTo() definiert die Genauigkeit beim Vergleich numerischer Werte, wobei zuerst gerundet und dann verglichen wird. </li><li>toHaveBeenCalled() prüft, ob die Funktion aufgerufen wurde </li><li>toHaveBeenCalledWith() prüft, ob der eingehende Parameter als Parameter aufgerufen wurde </li><li>toMatch() ist äquivalent zu <code>new RegExp().test()</code></li><li>toNotMatch() ist äquivalent zu <code>!new RegExp().test()</code></li><li>toThrow( ) prüft, ob die Funktion einen Fehler auslöst </li></ul><p> und ob diese APIs zuvor <code>not</code> verwendet wurden, um eine negative Wertbeurteilung anzuzeigen. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">expect(true).not.toBe(false);</pre><div class="contentsignin">Nach dem Login kopieren</div></div><p>Diese Matcher können fast unseren täglichen Bedarf decken. Natürlich können Sie Ihren eigenen Matcher auch an spezielle Bedürfnisse anpassen. </p><p><span style="font-size: 18px;"><strong>Setup und Teardown</strong></span></p><p>Ein leistungsfähiger Testcode ist sehr wichtig, damit wir diese wiederholten Setup- und Teardown-Codes in die entsprechenden <code>beforeEach</code> und <code>afterEach</code> globalen Funktionen einfügen können. </p><p><code>beforeEach</code> bedeutet, bevor jede Spezifikation ausgeführt wird und umgekehrt. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">describe('demo test', () => {
let val: number = 0;
beforeEach(() => {
val = 1;
});
it('should be true', () => {
expect(val).toBe(1);
});
it('should be false', () => {
expect(val).not.toBe(0);
});
});</pre><div class="contentsignin">Nach dem Login kopieren</div></div><p><span style="font-size: 18px;"><strong>Datenfreigabe</strong></span></p><p>Wie im obigen Beispiel können wir die entsprechenden Variablen am Anfang jeder Testdatei definieren, <code>describe</code>, sodass jeder <code>it</code> sie intern teilen kann. </p><p>Natürlich wird jeder Spec-Ausführungszyklus auch von einem leeren <code>this</code>-Objekt begleitet, bis es nach Ende der Spec-Ausführung gelöscht wird. Daten können auch mit <code>this</code> geteilt werden. </p><p><span style="font-size: 18px;"><strong>Verschachtelter Code</strong></span></p><p>Wenn wir eine Komponente testen, hat die Komponente manchmal unterschiedliche Zustände, um unterschiedliche Ergebnisse zu zeigen. Zu diesem Zeitpunkt erscheint die Verwendung nur eines <code>describe</code> zu elegant. </p><p>Durch die Verschachtelung <code>describe</code> sehen der Testcode und der Testbericht daher schöner aus. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">describe('AppComponent', () => {
describe('Show User', () => {
it('should be show panel.', () => {});
it('should be show avatar.', () => {});
});
describe('Hidden User', () => {
it('should be hidden panel.', () => {});
});
});</pre><div class="contentsignin">Nach dem Login kopieren</div></div><p><span style="font-size: 18px;"><strong>Überspringen Sie den Testcodeblock</strong></span></p><p>Die Anforderungen sind immer halbherzig, aber der Testcode, der schließlich geschrieben wurde, sollte gelöscht werden? Nein... </p><p>Suites und Specs können die globalen Funktionen <code>xdescribe</code> bzw. <code>xit</code> verwenden, um diese Testcodeblöcke zu überspringen. </p><p><span style="font-size: 20px;"><strong>3. Arbeiten Sie mit dem Angular-Werkzeugset zusammen</strong></span></p><p><span style="font-size: 18px;"><strong>Spy</strong></span></p><p><a href="https://img.php.cn/upload/article/000/000/024/5f45c5bc2de7d900.jpg" target="_blank">Angular</a>的自定义事件实在太普遍了,但为了测试这些自定义事件,因此监控事件是否正常被调用是非常重要。好在,<code>Spy</code> 可以用于监测函数是否被调用,这简直就是我们的好伙伴。</p><p>以下示例暂时无须理会,暂且体验一下:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">describe('AppComponent', () => {
let fixture: ComponentFixture<TestComponent>;
let context: TestComponent;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent]
});
fixture = TestBed.createComponent(TestComponent);
context = fixture.componentInstance;
// 监听onSelected方法
spyOn(context, 'onSelected');
fixture.detectChanges();
});
it('should be called [selected] event.', () => {
// 触发selected操作
// 断言是否被调用过
expect(context.onSelected).toHaveBeenCalled();
});
});</pre><div class="contentsignin">Nach dem Login kopieren</div></div><p><span style="font-size: 18px;"><strong>异步支持</strong></span></p><p>首先,这里的异步是指带有 Observable 或 Promise 的异步行为,因此对于组件在调用某个 Service 来异步获取数据时的测试状态。</p><p>假设我们的待测试组件代码:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">export class AppComponent {
constructor(private _user: UserService) {}
query() {
this._user.quer().subscribe(() => {});
}
}</pre><div class="contentsignin">Nach dem Login kopieren</div></div><p><strong>async</strong></p><p><code>async</code> 无任何参数与返回值,所有包裹代码块里的测试代码,可以通过调用 <code>whenStable()</code> 让<strong>所有待处理异步行为都完成后</strong>再进行回调;最后,再进行断言操作。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">it('should be get user list (async)', async(() => {
// call component.query();
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(true).toBe(true);
});
}));</pre><div class="contentsignin">Nach dem Login kopieren</div></div><p><strong>fakeAsync</strong></p><p>如果说 <code>async</code> 还需要回调才能进行断点让你受不了的话,那么 <code>fakeAsync</code> 可以解决这一点。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false">it('should be get user list (async)', fakeAsync(() => {
// call component.query();
tick();
fixture.detectChanges();
expect(true).toBe(true);
}));</pre><div class="contentsignin">Nach dem Login kopieren</div></div><p>这里只是将回调换成 <code>tick()</code>,怎么样,是不是很酷。</p><p><strong>Jasmine自带异步</strong></p><p>如前面所说的异步是指带有 Observable 或 Promise 的异步行为,而有时候我们有些东西是依赖 <code>setTimeout</code> 或者可能是需要外部订阅结果以后才能触发时怎么办呢?</p><p>可以使用 <code>done()</code> 方法。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">it('async demo', (done: () => void) => {
context.show().subscribe(res => {
expect(true).toBe(true);
done();
});
el.querySelected('xxx').click();
});</pre><div class="contentsignin">Nach dem Login kopieren</div></div><p><span style="font-size: 20px;"><strong>四、结论</strong></span></p>
<p>本章几乎所有的内容在Angular单元测试经常使用到的东西;特别是异步部分,三种不同异步方式并非共存的,而是需要根据具体业务而采用。否则,你会发现真TM难写单元测试。毕竟这是一个异步的世界。</p>
<p>自此,我们算是为Angular写单元测试打下了基础。后续,将不会再对这类基础进行解释。</p>
<p>happy coding!</p>
<p>相关教程推荐:<a href="https://www.php.cn/course/list/20.html" target="_blank">angular教程</a></p>
Das obige ist der detaillierte Inhalt vonEinführung in Angular-Unit-Tests mit Jasmine. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!