1 Giới thiệu
Automation testing là một quá trình tự động chạy các bước thực hiện một test case bằng máy, giúp giảm thiểu lỗi, thời gian cũng như sự nhàm chán với việc manual testing. Đặt biệt khi về cuối dự án, số lượng test case nhiều thì việc test hồi quy sẽ tốn rất nhiều thòi gian. Hơn nữa khi hệ thống có nhiều ngôn ngữ khác nhau thì sẽ gây khó khăn cho các tester và dễ xảy ra sai xót.
Là một developer, thường thì chúng ta chỉ viết unit test trong dự án, tuy nhiên unit test chỉ giúp chúng ta cover được các dòng code (line of codes), các input và output của các function mà chúng ta đã viết chứ chưa cover được các hành động, thao tác của người dùng đối với hệ thống. Và ở phiên bản 5.4, laravel đã ra mắt một tính năng mới là laravel dusk để giúp chúng ta thực hiện điều này.
2 cài đặt
2.1 Project
Bước đầu tiên là chuẩn bị một project để thực hiện test, ở đây mình đã chuẩn bị sẵn một project mẫu gồm các chức năng đăng nhập, đăng ký, và thêm sửa xóa cơ bẩn để phục vụ cho việc test. Các bạn có thể clone về tại đây
2.2 Cài đặt package Laravel dusk
Thêm package laravel dusk bằng lệnh sau:
1 2 | composer require --dev laravel/dusk |
Và cài đặt
1 2 | php artisan dusk:install |
Sau khi chạy lệnh trên, Laravel sẽ tạo một thư mục tests/Browser chứa các test case mấu, đồn thời tải và cài đặt chrome driver. Trường hợp chạy lệnh bị lỗi do không tương thích phiên bản chrome thì có thể thử theo một số cách sau:
- Cập nhật google chrome lên phiên bản mới nhất và sau đó chạy lại
1 2 | <span class="token function">sudo</span> <span class="token function">apt-get</span> --only-upgrade <span class="token function">install</span> google-chrome-stable |
- Kiểm tra phiên bản chrome hiện tại trên máy bạn (vào google chrome -> Help -> About Google Chrome) và cài đặt chrome dirver với phiên bản tương ứng bằng lệnh, vd: chrome 79.0.3945.88
1 2 | php artisan dusk:chrome-driver 79 |
2.3 Cấu hình
Chúng ta hãy cùng xem phương thức driver trong file DuskTestCase.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token comment">/** * Create the RemoteWebDriver instance. * * @return FacebookWebDriverRemoteRemoteWebDriver */</span> <span class="token keyword">protected</span> <span class="token keyword">function</span> <span class="token function">driver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$options</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ChromeOptions</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">addArguments</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token single-quoted-string string">'--headless'</span><span class="token punctuation">,</span> <span class="token single-quoted-string string">'--start-maximized'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ....</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
$options là một tập hợp các tùy chọn khi chạy test, mặc định sẽ có các option --headless
là không bật trình duyệt để mô phỏng khi chạy test, --start-maximized
bật chrome với kích thước full màn hình để mô phỏng khi chạy test, các bạn có thể tham khảo thêm các option khác tại đây. Ở đây mình sẽ bỏ option --headless
để bật trình duyệt để mô phỏng khi chạy test. Code của mình sẽ như sau
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token comment">/** * Create the RemoteWebDriver instance. * * @return FacebookWebDriverRemoteRemoteWebDriver */</span> <span class="token keyword">protected</span> <span class="token keyword">function</span> <span class="token function">driver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$options</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ChromeOptions</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">addArguments</span><span class="token punctuation">(</span><span class="token punctuation">[</span> <span class="token single-quoted-string string">'--start-maximized'</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> RemoteWebDriver<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">create</span><span class="token punctuation">(</span> <span class="token single-quoted-string string">'http://localhost:9515'</span><span class="token punctuation">,</span> DesiredCapabilities<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">chrome</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">setCapability</span><span class="token punctuation">(</span> ChromeOptions<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token constant">CAPABILITY</span><span class="token punctuation">,</span> <span class="token variable">$options</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
2.3 File env
Mặc định Laravel dusk sẽ sử dụng các biến môi trường trong file .env của dự án, để quản lý các biến môi trường riêng cho laravel dusk, ta copy file .env.example thành một file tên là .env.dusk. Trong bài viết này mình chạy test ở localhost nên sẽ sủa lại biến APP_URL như sau:
.env.dusk
1 2 3 4 5 6 | APP_NAME=Laravel APP_ENV=local APP_KEY= APP_DEBUG=true APP_URL=http://localhost:8000 |
3 Viết test
Giờ chúng ta sẽ tiến hành viết test. Đầu tiên mình sẽ xóa file ExampleTest.php trong thư mục tests/Browser vì ở ví dụ này mình sẽ test chức năng đăng ký của dự án này.
với bốn field name, email, pasword, password confirmation với code html tương ứng như sau:
1 2 3 4 5 6 7 8 | <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>name<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form-control @error(<span class="token punctuation">'</span>name<span class="token punctuation">'</span>) is-invalid @enderror<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>name<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{{ old(<span class="token punctuation">'</span>name<span class="token punctuation">'</span>) }}<span class="token punctuation">"</span></span> <span class="token attr-name">required</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form-control @error(<span class="token punctuation">'</span>email<span class="token punctuation">'</span>) is-invalid @enderror<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>email<span class="token punctuation">"</span></span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>{{ old(<span class="token punctuation">'</span>email<span class="token punctuation">'</span>) }}<span class="token punctuation">"</span></span> <span class="token attr-name">required</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form-control @error(<span class="token punctuation">'</span>password<span class="token punctuation">'</span>) is-invalid @enderror<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">required</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password-confirm<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>form-control<span class="token punctuation">"</span></span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>password_confirmation<span class="token punctuation">"</span></span> <span class="token attr-name">required</span> <span class="token attr-name">autocomplete</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>new-password<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> |
Tạo file test chức năng đăng ký bằng lệnh
1 2 | php artisan dusk:make RegisterTest |
Laravel dusk sẽ sinh ra một file RegisterTest.php
trong thư mục tests/Browser với nội dung như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">Tests<span class="token punctuation"></span>Browser</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation"></span>Foundation<span class="token punctuation"></span>Testing<span class="token punctuation"></span>DatabaseMigrations</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Laravel<span class="token punctuation"></span>Dusk<span class="token punctuation"></span>Browser</span><span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Tests<span class="token punctuation"></span>DuskTestCase</span><span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">RegisterTest</span> <span class="token keyword">extends</span> <span class="token class-name">DuskTestCase</span> <span class="token punctuation">{</span> <span class="token comment">/** * A Dusk test example. * * @return void */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">testExample</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">browse</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span>Browser <span class="token variable">$browser</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$browser</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">visit</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'/'</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">assertSee</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Laravel'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
Mình sẽ xóa test example và thay bằng các test case của mình
- Test truy cập vào trang Register và kiểm tra xem có các element hay không
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <span class="token comment">/** * Test go to register page and see elements. * * @return void */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">testGoToRegisterPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">browse</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span>Browser <span class="token variable">$browser</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$browser</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">visit</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'/register'</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">assertSee</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'Register'</span><span class="token punctuation">)</span> <span class="token comment">// Tìm element bằng thuộc tính name</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">assertPresent</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'input[name="name"]'</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">assertPresent</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'input[name="email"]'</span><span class="token punctuation">)</span> <span class="token comment">// Tìm element bằng thuộc tính id</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">assertPresent</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'#password'</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">assertPresent</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'#password-confirm'</span><span class="token punctuation">)</span> <span class="token comment">// Tìm element bằng thuộc tính class</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">assertPresent</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'.btn-primary'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
- Test chức năng đăng ký
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <span class="token comment">/** * Test register feature works corectly. * * @return void */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">testRegisterFeature</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">browse</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span>Browser <span class="token variable">$browser</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$password</span> <span class="token operator">=</span> <span class="token single-quoted-string string">'<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="044565443536373031">[email protected]</a>'</span><span class="token punctuation">;</span> <span class="token variable">$faker</span> <span class="token operator">=</span> Faker<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$name</span> <span class="token operator">=</span> <span class="token variable">$faker</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">name</span><span class="token punctuation">;</span> <span class="token variable">$browser</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">visit</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'/register'</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">type</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'name'</span><span class="token punctuation">,</span> <span class="token variable">$name</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">type</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'email'</span><span class="token punctuation">,</span> <span class="token variable">$faker</span><span class="token operator">-</span><span class="token operator">></span><span class="token property">email</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">type</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'password'</span><span class="token punctuation">,</span> <span class="token variable">$password</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">type</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'password_confirmation'</span><span class="token punctuation">,</span> <span class="token variable">$password</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">click</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'.btn-primary'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token variable">$browser</span><span class="token operator">-</span><span class="token operator">></span><span class="token function">assertSeeLink</span><span class="token punctuation">(</span><span class="token variable">$name</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span><span class="token function">assertPathIs</span><span class="token punctuation">(</span><span class="token single-quoted-string string">'/home'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Và chạy lệnh sau để chạy các test case
1 2 | php artisan dusk |
Và kết quả
Test result
4 Kết
Trên đây là các bước cài đặt và ví dụ sơ bộ về Laravel dusk, ở phấn tiếp theo mình sẽ giới thiệu về các phần khác nhưu cách tương tác với các element, cách cấu trúc thư mục… Cảm ơn các bạn đã quan tâm theo dõi, hẹn gặp lại ở các phần sau
Tham khảo