Cách kiểm tra các thành phần phản ứng với Jest và Enzyme, Phần 1

https://helpex.vn/article/cach-kiem-tra-cac-thanh-phan-phan-ung-voi-jest-va-enzyme-phan-1-5c54ddfd507419248c9b0108

Kiểm tra các thành phần React có thể là thách thức đối với người mới bắt đầu và các nhà phát triển có kinh nghiệm, những người đã làm việc với các thử nghiệm. Thật thú vị khi so sánh các phương pháp của riêng bạn với các phương pháp chúng tôi sử dụng trong dự án của chúng tôi. Để bao trùm cơ sở mã, bạn phải biết thành phần nào phải được kiểm tra và mã nào chính xác trong một thành phần cần được bảo hiểm.

Trong quá trình đọc, tôi sẽ đề cập đến các chủ đề tiếp theo:

  • Xác định thứ tự đúng của thử nghiệm các thành phần dựa trên cấu trúc dự án.

  • Tìm những gì cần bỏ qua trong phạm vi kiểm tra (những gì không kiểm tra).

  • Xác định sự cần thiết của Kiểm tra chụp nhanh.

  • Xác định những gì cần kiểm tra trong thành phần và theo thứ tự.

  • Cung cấp các ví dụ mã tùy chỉnh chi tiết.

Bài viết yêu cầu người đọc đã có kiến ​​thức về Jest và Enzyme. Thông tin về cài đặt và cấu hình có thể dễ dàng tìm thấy trên web hoặc trên các trang web chính thức.

Giả sử như sau: Bạn cần bao gồm các cơ sở mã dự án bằng các bài kiểm tra. Vì vậy, những gì bạn nên bắt đầu với và những gì bạn nên nhận được khi kết thúc thử nghiệm? Bảo hiểm 100% kiểm tra? Đó là chỉ số mà bạn nên khao khát, nhưng trong hầu hết các tình huống, bạn sẽ không nhận được nó. Tại sao? Bởi vì bạn không nên kiểm tra tất cả các mã. Chúng tôi sẽ tìm hiểu lý do tại sao và những gì nên bỏ qua các bài kiểm tra. Thậm chí, phạm vi kiểm tra 100% không phải lúc nào cũng đảm bảo rằng thành phần được kiểm tra đầy đủ. Đồng thời, không có gì đảm bảo nó sẽ thông báo cho bạn nếu có gì đó bị thay đổi. Đừng phấn đấu cho tỷ lệ phần trăm, tránh viết bài kiểm tra giả và chỉ cố gắng không để mất chi tiết thành phần chính.

Xác định thứ tự đúng của kiểm tra thành phần dựa trên cấu trúc dự án

Chúng ta hãy thảo luận câu hỏi này về phần tiếp theo của cấu trúc dự án:

Tôi lấy sharedthư mục vì nó là quan trọng nhất; nó bao gồm các thành phần được sử dụng trong một số trang khác nhau của dự án. Chúng có thể tái sử dụng và, thông thường, chúng nhỏ và không phức tạp. Nếu một hoặc một thành phần khác thất bại, nó sẽ gây ra thất bại ở những nơi khác. Đó là lý do tại sao chúng ta nên tự tin rằng họ đã được viết chính xác. Cấu trúc của thư mục này được chia thành nhiều thư mục, mỗi thư mục chứa các thành phần.

Cách xác định thứ tự đúng của kiểm tra thành phần trong sharedthư mục:

  • Luôn tuân theo quy tắc từ đơn giản đến phức tạp. Phân tích từng thư mục và xác định các thành phần nào independent- cụ thể là kết xuất của chúng không phụ thuộc vào các thành phần khác; chúng tự hoàn thành và có thể được sử dụng riêng lẻ như một đơn vị. Từ cấu trúc trên, nó là inputsthư formsmục trong thư mục. Nó chứa các thành phần đầu vào cho các biểu mẫu redux, chẳng hạn như TextInput, SelectInput, CheckboxInput, DateInput, v.v.

  • Tiếp theo, tôi cần xác định các thành phần phụ trợ thường được sử dụng trong inputscác thành phần, nhưng nên được kiểm tra ngoài chúng. Nó là utilsthư mục. Các thành phần trong thư mục này không phức tạp, nhưng rất quan trọng. Chúng thường xuyên được tái sử dụng và giúp đỡ với các hành động lặp đi lặp lại.

  • Bước tiếp theo là xác định thành phần nào cũng có thể được sử dụng độc lập. Nếu có, hãy mang chúng đi thử nghiệm. Từ cấu trúc của chúng tôi, đó là widgets, các thành phần nhỏ với chức năng đơn giản. Chúng sẽ là mục thứ ba trong hàng đợi cho phạm vi kiểm tra.

  • Hơn nữa, phân tích phần còn lại của các thư mục và xác định các thành phần phức tạp hơn, có thể được sử dụng độc lập hoặc kết hợp với các thành phần khác. Đây là modalsthư mục trong trường hợp của chúng tôi; các thành phần này sẽ được giải thích chi tiết dưới đây.

  • Sự phức tạp nhất để kiểm tra các thành phần được để lại cuối cùng. Chúng là hocthư mục và fieldstừ formsthư mục. Làm thế nào để bạn xác định cái nào nên được thử nghiệm đầu tiên? Tôi lấy thư mục mà các thành phần đã được sử dụng trong các thành phần được thử nghiệm. Do đó, thành phần từ hocthư mục đã có mặt trong widgetsthành phần; đó là lý do tại sao tôi đã biết thư mục này và thành phần của nó được sử dụng ở đâu và với mục đích gì.

  • Cái cuối cùng là fieldsthư mục; nó chứa các thành phần được kết nối với các hình thức redux.

Thứ tự các thành phần cuối cùng (dựa trên ví dụ của chúng tôi) sẽ trông như thế này:

Theo thứ tự này, bạn tăng dần độ phức tạp của các thành phần được kiểm tra; do đó, khi nói đến hoạt động với các thành phần phức tạp hơn, bạn đã biết các bộ phận nhỏ nhất hoạt động như thế nào. Đừng lấy trường 'mảng' để kiểm tra, ví dụ, nếu bạn không chắc chắn cách kiểm tra trường 'văn bản'; không lấy các thành phần được trang trí bằng các biểu mẫu redux nếu bạn chưa kiểm tra trường 'biểu mẫu'. Hãy nhất quán trong các lựa chọn của bạn, đừng lấy thành phần đầu tiên xuất hiện trong đầu bạn và bật logic. Tất nhiên, cấu trúc của dự án của bạn có thể khác nhau; nó có thể có các tên thư mục khác hoặc có thể có các thành phần, hành động và bộ giảm tốc bổ sung, nhưng logic xác định thứ tự để kiểm tra các thành phần là như nhau.

Hãy xác định những gì nên được bỏ qua trong phạm vi kiểm tra:

  1. Thư viện của bên thứ ba . Đừng kiểm tra chức năng được lấy từ thư viện khác; bạn không chịu trách nhiệm cho mã đó. Bỏ qua nó hoặc bắt chước thực hiện nếu bạn cần nó để kiểm tra mã của bạn.

  2. Hằng số . Tên nói cho chính nó. Họ không thể thay đổi; nó là một tập hợp các mã tĩnh không có ý định thay đổi.

  3. Kiểu nội tuyến (nếu bạn sử dụng chúng làm thành phần). Để kiểm tra các kiểu nội tuyến, bạn cần sao chép đối tượng với các kiểu trong thử nghiệm của mình; nếu đối tượng kiểu thay đổi, bạn cũng phải thay đổi nó trong thử nghiệm. Không sao chép mã của một thành phần trong các thử nghiệm. Trong hầu hết các trường hợp, kiểu nội tuyến không thay đổi hành vi của thành phần; do đó, họ không nên được thử nghiệm. Có thể có một ngoại lệ trong trường hợp phong cách của bạn thay đổi linh hoạt.

  4. Những thứ không liên quan đến thành phần được thử nghiệm . Bỏ qua bao phủ với các thành phần thử nghiệm đã được nhập khẩu vào thành phần được thử nghiệm; hãy cẩn thận nếu nó được bọc trong một cái khác Đừng kiểm tra các hàm bao, chỉ cần phân tích và kiểm tra chúng một cách riêng biệt.

Vì vậy, làm thế nào để bạn thực sự viết bài kiểm tra? Tôi kết hợp hai phương pháp thử nghiệm:

  • Kiểm tra chụp nhanh.

  • Kiểm tra logic thành phần.

Kiểm tra ảnh chụp là một công cụ kiểm tra hữu ích trong trường hợp bạn muốn chắc chắn giao diện người dùng không thay đổi. Khi đối mặt với công cụ kiểm tra này lần đầu tiên, các câu hỏi phát sinh liên quan đến tổ chức và quản lý ảnh chụp nhanh. Nguyên tắc làm việc rất đơn giản, nhưng thật không may, nó chưa được mô tả đầy đủ ở bất cứ đâu; trên trang web chính thức, jestjs.io , mô tả về công việc Kiểm tra ảnh chụp rất kém.

Cách kiểm tra với ảnh chụp nhanh

Bước 1. Viết một bài kiểm tra cho thành phần và, trong expect, sử dụng .toMatchSnapshot()phương thức tạo ra Snapshotchính nó.

it('render correctly text component', () => {      const TextInputComponent = renderer.create(<textinput></textinput>).toJSON();    expect(TextInputComponent).toMatchSnapshot();});

Bước 2. Khi bạn chạy thử nghiệm lần đầu tiên ở một cấp độ, cùng với thử nghiệm, sẽ có một thư mục được tạo, được đặt tên __snapshots__, với tệp được tạo tự động bên trong có phần mở rộng .snap.

Ảnh chụp trông giống như:

// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Render TextInput correctly component 1`] = `  <input classname="input-custom" disabled="{undefined}" id="{undefined}" name="{undefined}" onblur="{undefined}" onchange="{[Function]}" pattern="{undefined}" placeholder="{undefined}" readonly="{false}" required="{undefined}" type="text" value="{undefined}">`;

Bước 3. Đẩy ảnh chụp nhanh vào kho lưu trữ và lưu trữ cùng với bài kiểm tra.

Nếu thành phần đã được thay đổi, bạn chỉ cần cập nhật Ảnh chụp nhanh với —updateSnapshotcờ hoặc bằng cách sử dụng ucờ dạng ngắn .

Ảnh chụp được tạo, nhưng nó hoạt động như thế nào?

Chúng ta hãy xem xét hai trường hợp:

1. Thành phần đã thay đổi

  • Chạy thử nghiệm.

  • Ảnh chụp nhanh mới được tạo và nó so sánh với ảnh chụp nhanh được tạo tự động được lưu trong thư mục __snapshots__

  • Các thử nghiệm thất bại vì một ảnh chụp nhanh là khác nhau.

2. Thành phần không thay đổi

  • Chạy thử nghiệm.

  • Ảnh chụp nhanh mới được tạo, so sánh các thử nghiệm với Ảnh chụp nhanh được tạo tự động được lưu trữ trong thư mục __snapshots__

  • Các bài kiểm tra đã vượt qua vì Ảnh chụp giống hệt nhau.

Mọi thứ đều ổn khi tôi kiểm tra một thành phần nhỏ không có logic, chỉ hiển thị giao diện người dùng, nhưng, như thực tế cho thấy, không có thành phần nào như vậy trên các dự án thực. Nếu có, họ ở số lượng nhỏ.

Có đủ để chạy thử nghiệm thành phần đầy đủ?

Hướng dẫn chính để kiểm tra thành phần

1. Một thành phần chỉ nên có một ảnh chụp nhanh. Nếu một ảnh chụp nhanh thất bại, rất có thể những ảnh chụp khác cũng sẽ thất bại, vì vậy đừng tạo và lưu trữ một loạt ảnh chụp nhanh không cần thiết làm tắc nghẽn không gian và gây nhầm lẫn cho các nhà phát triển sẽ đọc bài kiểm tra của bạn sau bạn. Tất nhiên, có những trường hợp ngoại lệ khi bạn cần kiểm tra hành vi của một thành phần ở hai trạng thái; ví dụ, ở trạng thái của thành phần trước khi mở cửa sổ bật lên và sau khi mở. Tuy nhiên, ngay cả các biến thể như vậy luôn có thể được thay thế bằng cái này: thử nghiệm đầu tiên lưu trữ trạng thái mặc định của thành phần mà không có cửa sổ bật lên trong thử nghiệm và thử nghiệm thứ hai mô phỏng các sự kiện và kiểm tra sự hiện diện của một lớp cụ thể. Bằng cách này, bạn có thể dễ dàng bỏ qua việc tạo một số ảnh chụp nhanh.

2. Kiểm tra đạo cụ: Theo quy định, tôi chia việc kiểm tra đạo cụ thành hai bài kiểm tra. Đầu tiên, kiểm tra kết xuất của các giá trị prop mặc định; khi thành phần được kết xuất, tôi hy vọng một giá trị sẽ bằng với defaultPropstrong trường hợp prop này có defaultProps. Thứ hai, kiểm tra giá trị tùy chỉnh của prop; Tôi đặt giá trị của riêng mình và hy vọng nó sẽ được nhận sau khi kết xuất thành phần.

3. Kiểm tra loại dữ liệu: Để kiểm tra loại dữ liệu nào có trong đạo cụ hoặc loại dữ liệu nào được lấy sau một số hành động nhất định, tôi sử dụng thư viện đặc biệt được mở rộng (bộ so khớp Jest bổ sung), có bộ khớp nối mở rộng vắng mặt trong Jest. Với thư viện này, việc kiểm tra các loại dữ liệu dễ dàng và thú vị hơn nhiều. Nguyên mẫu thử nghiệm là một câu hỏi mâu thuẫn. Một số nhà phát triển có thể lập luận chống lại thử nghiệm nguyên mẫu vì đây là gói của bên thứ ba và không nên thử nghiệm, nhưng tôi khăng khăng thử nghiệm các nguyên mẫu của các thành phần vì tôi không tự kiểm tra chức năng của gói; Tôi chỉ đảm bảo các nguyên mẫu là chính xác. Kiểu dữ liệu là một khái niệm lập trình rất quan trọng và không nên bỏ qua.

4. Kiểm tra sự kiện: Sau khi tạo ảnh chụp nhanh và che các đạo cụ bằng các thử nghiệm, bạn có thể chắc chắn về kết xuất không chính xác của thành phần, nhưng điều này là không đủ để bảo hiểm đầy đủ trong trường hợp bạn có các sự kiện trong thành phần. Bạn có thể kiểm tra sự kiện theo nhiều cách; được sử dụng rộng rãi nhất là:

  • sự kiện giả => mô phỏng nó => sự kiện mong đợi đã được gọi

  • sự kiện giả định => mô phỏng sự kiện với params => sự kiện mong đợi được gọi với thông số đã qua

  • vượt qua các đạo cụ cần thiết => kết xuất thành phần => mô phỏng sự kiện => mong đợi một hành vi nhất định đối với các sự kiện được gọi

5. Điều kiện kiểm tra: Rất thường xuyên bạn có thể có các điều kiện cho đầu ra của một lớp cụ thể, hiển thị một phần nhất định của mã, chuyển các đạo cụ cần thiết, v.v. Đừng quên điều này bởi vì, với các giá trị mặc định, chỉ có một nhánh sẽ vượt qua bài kiểm tra, trong khi nhánh thứ hai sẽ không được kiểm tra. Trong các thành phần phức tạp với các tính toán và nhiều điều kiện, bạn có thể bỏ lỡ một số nhánh. Để đảm bảo tất cả các phần của mã được bao phủ bởi các thử nghiệm, hãy sử dụng các công cụ bao phủ thử nghiệm và kiểm tra trực quan các nhánh nào được bảo hiểm và các nhánh nào không.

6. Kiểm tra trạng thái : Để kiểm tra trạng thái, trong hầu hết các trường hợp, cần phải viết hai bài kiểm tra:

  • Cái đầu tiên kiểm tra trạng thái hiện tại.

  • Cái thứ hai kiểm tra trạng thái sau khi gọi một sự kiện. Kết xuất thành phần => chức năng gọi trực tiếp trong thử nghiệm => kiểm tra trạng thái đã thay đổi như thế nào. Để gọi một hàm của thành phần, bạn cần lấy một thể hiện của thành phần và chỉ sau đó gọi các phương thức của nó (một ví dụ được hiển thị trên GitHub, ở đây ).

Sau khi bạn xem qua danh sách hướng dẫn này, thành phần của bạn sẽ được bảo hiểm từ 90 đến 100%. Tôi để lại 10% cho các trường hợp đặc biệt không được mô tả trong bài viết nhưng có thể xảy ra trong mã.

Đó là tất cả cho Phần 1. Điều chỉnh lại vào ngày mai khi chúng ta đi sâu vào một số mã!

3 hữu ích0 bình luận2.2k xemchia sẻ

CÓ THỂ BẠN QUAN TÂM

(Bài viết giả định ít nhất bạn có kiến ​​thức cơ bản về Angular. Angular là một framework rất kiên định, vì vậy hãy đảm bảo bạn có một số kinh nghiệm với Angular trước khi làm theo các hướng dẫn được trình bày bên dưới.)

Các bản ghi có thể tích hợp vào bất kỳ khuôn khổ Javascript nào bạn muốn sử dụng. Trước đây, chúng tôi đã kiểm tra việc thêm Logentries vào một ứng dụng React . Bài đăng này sẽ minh họa cách thêm Thông tin đăng nhập vào ứng dụng Angular v1 của bạn bằng cách sử dụng Nhà cung cấp. Kiến trúc Nhà cung cấp của Angular v1 cung cấp một cách mô-đun và mạnh mẽ để thêm chức năng vào các ứng dụng Angular của bạn.

Kiến trúc Angular Provider là một trong những thiết bị tuyệt vời của Angular v1. Tài liệu dành cho Nhà cung cấp có tại đây . Trình cung cấp là các đối tượng độc lập được đưa vào và sử dụng bên trong các ứng dụng Angular. Chúng là các khối xây dựng của hầu hết các ứng dụng Angular và thực thi một cấu trúc mô-đun thúc đẩy việc tái sử dụng và làm sạch mã. Có một số loại Nhà cung cấp; chúng ta sẽ sử dụng loại Factory.

Angular Factory là một đối tượng tùy chỉnh được tạo bằng phương pháp Angular factory. Chuyển một nhà máy vào mô-đun Angular của bạn thông qua quá trình tiêm sẽ làm cho đối tượng tùy chỉnh của bạn có thể truy cập bên trong mô-đun. Thông thường, Factory được sử dụng để tạo một đối tượng chỉ được tạo một lần và trả về một đối tượng được chia sẻ. Dịch vụ phía máy khách Logentries rất phù hợp với mẫu Factory vì nó cũng hoạt động như một tài nguyên được chia sẻ. Phần lớn mã được sử dụng trong nhà máy là để khởi tạo đối tượng Logentries. Sau khi khởi tạo, Factory sẽ hiển thị đối tượng Logentries.

Hãy bắt đầu bằng cách xem index.html:

<body ng-app="LeAngularSample"><selection></selection><script src="vendor/angular.min.js"></script><script src="vendor/le.min.js"></script><script src="LogEntriesFactory.js"></script><script src="app.js"></script></body>

Thẻ ng-app xác định mô-đun chính mà Angular đang tải vào phần thân. LeAngularSample là mô-đun mẫu đang được sử dụng để minh họa thư viện. LogEntriesFactory.js giới thiệu thư viện Logentries. Mã trong app.js chèn và sử dụng mã Logentries, đồng thời chèn thành phần giao diện người dùng của mẫu vào thẻ “<selection>” tùy chỉnh. Các thẻ còn lại bổ sung các thư viện javascript cần thiết.

Index.html là trang mở đầu. Hãy xem các tệp script đang được nhập, bắt đầu với tệp LogEntriesFactory.js:

angular.module('LogEntries',[]).factory('LoggerFactory', function (){  var opts = {};  opts.token = '1234_fake_token';  LE.init(opts);  return LE;})

Mã bắt đầu bằng cách tạo một mô-đun Angular mới có tên là “LogEntries”. Mô-đun này là một mô-đun Angular độc lập có khả năng được sử dụng ở mọi nơi. Tệp này có thể được gỡ bỏ từ ứng dụng này và được chèn vào bất kỳ ứng dụng nào.

Mô-đun tạo một đối tượng được gọi là LoggerFactory. LoggerFactory được sử dụng trong mã để tương tác với đối tượng Logentries. LoggerFactory khởi động, đặt mã thông báo Logentries, khởi tạo đối tượng trên mỗi tài liệu Logentries và trả về đối tượng Logentries đã chuẩn bị.

Tệp script khác chứa chỉ thị. Chỉ thị trông như thế này:

angular.module('LeAngularSample', ['LogEntries']).directive('selection', function (){  return {    restrict: 'E',    transclude: true,    scope: {},    templateUrl: 'template.html',    controller: function ($scope, LoggerFactory){      $scope.sendError = function (msg){        LoggerFactory.error('Error: ' + msg);      };      $scope.sendWarn = function (msg){        LoggerFactory.warn('Warn: ' + msg);      };      $scope.sendInfo = function (msg){        LoggerFactory.info('Info: ' + msg);      };      $scope.sendLog = function (msg){        LoggerFactory.log('Log: ' + msg);      };    }  }})

Chỉ thị là cơ chế của Angular để tạo các phần tử giao diện người dùng. Chỉ thị của chúng tôi thay thế thẻ <selection> bằng nội dung của HTML trong tệp template.html (được hiển thị bên dưới). Các đoạn mã thú vị nhất cho mục đích của chúng tôi là:

  • Injector - angle.module ('LeAngularSample', [ 'LogEntries' ]) LogEntries là tên của mô-đun có chứa LoggerFactory. Dòng này yêu cầu Angular đưa mô-đun LogEntries vào mô-đun LeAngularSample và làm cho các thành phần của mô-đun LogEntries có thể truy cập được.

  • templateUrl - templateUrl: 'template.html'Angular thay thế thẻ lựa chọn bằng nội dung của tệp mẫu tại templateUrl

  • controller - controller: function ($ scope, LoggerFactory) {Bộ điều khiển bao gồm mã được gọi bởi các thành viên của chỉ thị lựa chọn. Lưu ý rằng các chức năng trong bộ điều khiển được gọi trong ng-click của mẫu. Mỗi liên kết từ mẫu sẽ gọi chức năng đối ứng của nó từ bộ điều khiển. LoggerFactory có thể được bao gồm vì mô-đun đã được đưa vào ở trên. Nó nằm trong các tham số chức năng của bộ điều khiển nên nó có thể được sử dụng trong mã của bộ điều khiển.

Tệp html mẫu trông như thế này (với một số văn bản đã bị xóa):

<div>….</div><div style= "display: flex; flex-direction: column; width:200px">  <a href="#" ng-click="sendError('Oops')">Submit Error</a>  <a href="#" ng-click="sendWarn('Warning!')">Submit Warning</a>  <a href="#" ng-click="sendInfo('Info')">Submit Info</a>  <a href="#" ng-click="sendLog('Logging')">Submit Log</a></div>

Lưu ý bốn dòng với ng-click. Các lệnh ng-click được hiển thị dưới dạng các sự kiện nhấp chuột. Bốn chức năng tương ứng trực tiếp với các phương thức được gọi trong mã bộ điều khiển của chỉ thị. Angular sẽ tự động liên kết các chức năng trong ng-click với chỉ thị.

Mẫu đi kèm với một thiết lập máy chủ nút để hiển thị trang. README có hướng dẫn cách bắt đầu. Sau khi thiết lập và chạy, trang sẽ giống như hình dưới đây. Sử dụng bất kỳ liên kết nào trong số này sẽ gửi nhật ký đến tài khoản Logentries của bạn với loại tương ứng.

Ràng buộc Logentries vào mã Angular của bạn cũng đơn giản như việc đưa vào một mô-đun. Hãy sử dụng LogEntriesFactory.js và sửa đổi nó để hoạt động trong ứng dụng Angular của bạn. Việc đưa thư viện phía máy khách Logentries vào mã của bạn thật dễ dàng nhờ vào các thành phần mô-đun và chèn của Angular.

Bạn có thể tìm thấy repo GitHub với đầy đủ mẫu tại https://github.com/LogentriesCommunity/Logentries-Angular-Sample

9 hữu ích0 bình luận4.8k xemchia sẻ

Tôi đã lấy kho lưu trữ GitHub cho hoạt động của Khái niệm web ( @dret ) của Erik Wilde và phân nhánh nó, sau đó tạo một số JSON mà tôi có thể sử dụng để nhập vào hệ thống giám sát API của mình. Tôi đã thêm thông số kỹ thuật vào hệ thống lập lịch Tweet và LinkedIn của mình theo cách thủ công, nhưng tôi vẫn quên quay lại trang web và thêm các mục khác. Vì vậy, tôi muốn tiếp tục và nhập tất cả các khái niệm và thông số kỹ thuật, đồng thời lên lịch cho các bài đăng trên Twitter và LinkedIn cho mọi thứ, trong vài tháng tới.

Đầu tiên, tôi tạo JSON cho các khái niệm, sau đó tôi tạo JSON cho các thông số kỹ thuật, bạn có thể xem ở đây.

Tôi đã bỏ qua các mối quan hệ giữa các khái niệm và thông số kỹ thuật, vì tôi sẽ chỉ liên kết đến Các khái niệm web và để mọi người tự khám phá. Khi tôi xem qua JSON, tôi nghĩ về lý do tại sao những khái niệm và thông số kỹ thuật này không có sẵn trong công cụ thiết kế API dưới dạng trợ giúp và chú giải công cụ, để các nhà thiết kế và kiến ​​trúc sư API có thể học hỏi từ chúng và được nhắc nhở trong thời gian thực — tạo ra các API của họ.

Có vẻ như cần có tính năng tự động hoàn thành cho các trường tiêu đề HTTP, mã trạng thái HTTP và các mục liên quan khác nếu cần. Có rất nhiều kiến ​​thức về web trong công việc của Erik, và thông qua các khái niệm và thông số kỹ thuật web mà anh ấy đã sắp xếp, có vẻ như chúng sẽ có sẵn theo mặc định trong các dịch vụ và công cụ thiết kế API, và bắt đầu được đưa vào các IDE như Atom, Eclipse, và Visual Studio. Có lẽ họ đã có, và tôi chỉ không biết.

0 hữu ích0 bình luận3.1k xemchia sẻ

Trạng thái có thể thay đổi được chia sẻ là nguồn gốc của rất nhiều lỗi. Khi hai hoặc nhiều đối tượng sử dụng cùng một phần dữ liệu có thể thay đổi, tất cả chúng đều có khả năng phá vỡ lẫn nhau theo những cách khó có thể gỡ lỗi. Tuy nhiên, nếu dữ liệu được chia sẻ là bất biến, các đối tượng này không thể ảnh hưởng lẫn nhau và được tách rời một cách hiệu quả.

Bài viết này là một đánh giá về các tùy chọn có sẵn cho Rubyists liên quan đến tính bất biến. Chúng ta sẽ xem xét các tính năng tích hợp của Ruby 2.3 và một vài viên ngọc.

Cấp đông Lib tiêu chuẩn

Hãy bắt đầu với freezephương thức từ thư viện chuẩn:

Đối tượng # đóng băng

Ngăn chặn các sửa đổi thêm đối với obj. A RuntimeErrorsẽ được nâng lên nếu cố gắng sửa đổi. Không có cách nào để giải phóng một đối tượng bị đóng băng. Xem thêm Object#frozen?.

Phương thức này trả về tự.

a = [ "a", "b", "c" ]a.freezea << "z"

sản xuất:

prog.rb:3:in `<<': can't modify frozen Array (RuntimeError)from prog.rb:3

Đối tượng của các lớp sau đây luôn đông lạnh: Fixnum, Bignum, Float, Symbol.

Các freezephương pháp sẽ làm việc cho hầu hết các đối tượng, trong đó có trường hợp của các tầng lớp người dùng định nghĩa:

class Foo  def mutate_self    @x = 5  endend f = Foo.newf.freezef.mutate_self #=> RuntimeError: can't modify frozen Foo

Ngoại lệ duy nhất là các lớp kế thừa từ BasicObject. Các freezephương pháp được định nghĩa trên Object, vì vậy nó không phải là có sẵn với các trường hợp BasicObject:

class BasicFoo < BasicObject; endbf = BasicFoo.newbf.freeze #=> NoMethodError: undefined method `freeze' for #<BasicFoo:0x007f912b9c3060>

Bạn sẽ thường thấy freezeđược sử dụng khi gán hằng số, để đảm bảo rằng các giá trị không thể bị thay đổi. Điều này là do việc gán lại một biến hằng số sẽ tạo ra một cảnh báo, nhưng việc thay đổi một giá trị hằng số thì không .

module Family  NAMES = ['Tom', 'Dane']end # mutation is allowedFamily::NAMES << 'Alexander'p Family::NAMES #=> ["Tom", "Dane", "Alexander"] # reassignment triggers a warningFamily::NAMES = ['some', 'other', 'people']#=> warning: already initialized constant Family::NAMES

Vì vậy, nếu bạn muốn đảm bảo rằng các hằng số của bạn thực sự không đổi, bạn cần cố định giá trị:

module Family  NAMES = ['Tom', 'Dane'].freezeend

Vấn đề chính của freezephương pháp là nó nông , trái ngược với đệ quy. Ví dụ: một mảng cố định không thể có thêm, xóa hoặc thay thế các phần tử, nhưng bản thân các phần tử hiện tại vẫn có thể thay đổi:

module Family  NAMES = ['Tom', 'Dane'].freezeend Family::NAMES.first.upcase!p Family::NAMES #=> ["TOM", "Dane"]

Frozen String Literals Trong Ruby 2.3

Bạn có thể nhận thấy rằng các biểu tượng và số được tự động đóng băng trong Ruby. Ví dụ, không thể thực hiện add!phương pháp này :

x = 5x.add!(2)x == 7 #=> this can't be true

Trong hầu hết các ngôn ngữ, ký tự chuỗi cũng không thay đổi, giống như số và ký hiệu. Tuy nhiên, trong Ruby, tất cả các chuỗi đều có thể thay đổi theo mặc định.

Điều này sẽ thay đổi trong phiên bản chính tiếp theo của Ruby. Tất cả các ký tự chuỗi sẽ không thay đổi theo mặc định trong Ruby 3, nhưng điều đó vẫn còn vài năm nữa. Trong thời gian chờ đợi, chức năng này có thể được kích hoạt tùy chọn kể từ Ruby 2.3.

Có một tùy chọn dòng lệnh có sẵn cho phép các ký tự chuỗi cố định trên toàn cầu:

ruby --enable-frozen-string-literal whatever.rb

Thật không may, điều này sẽ phá vỡ rất nhiều mã và đá quý đã tồn tại trước đó, bởi vì hầu hết mã được viết với giả định rằng các ký tự chuỗi có thể thay đổi được.

Cho đến khi mã cũ hơn được cập nhật để xử lý các chuỗi bị cố định, tốt hơn nên bật tùy chọn này trên cơ sở từng tệp bằng cách sử dụng “nhận xét kỳ diệu” này ở đầu mỗi tệp:

# frozen_string_literal: true greeting = 'Hello'greeting.upcase! #=> RuntimeError: can't modify frozen String

Khi nhận xét kỳ diệu này tồn tại, chuỗi ký tự bên trong tệp sẽ bị đóng băng theo mặc định, nhưng mã trong các tệp khác sẽ không bị ảnh hưởng.

Khi bạn thực sự muốn một chuỗi có thể thay đổi, bạn phải tạo một String#newchuỗi bằng hoặc sao chép một chuỗi cố định bằng cách sử dụng String#dup:

# frozen_string_literal: true # this string is mutablex = String.new('Hello')x.upcase!puts x #=> 'HELLO' # and so is thisy = 'World'.dupy.upcase!puts y #=> 'WORLD'

Các ice_nineGem - Freezing Recursive

Nó chỉ ra rằng việc đóng băng một cách đệ quy một đối tượng đúng cách là một chút khó khăn, nhưng may mắn thay có một viên ngọc quý cho điều đó. Các ice_nineđá quý áp dụng freezephương pháp đệ quy, đảm bảo rằng một đối tượng là thực sự đông lạnh:

require 'ice_nine' module Family  NAMES = IceNine.deep_freeze(['Tom', 'Dane'])end Family::NAMES.first.upcase!#=> RuntimeError: can't modify frozen String

Đá quý cũng cung cấp một phần mở rộng cốt lõi tùy chọn để xác định Object#deep_freeze, để thuận tiện:

require 'ice_nine'require 'ice_nine/core_ext/object' module Family  NAMES = ['Tom', 'Dane'].deep_freezeend

Các valuesGem - Các lớp Immutable Struct-Like

Thay vì đóng băng các đối tượng có thể thay đổi, thường tốt hơn là tạo các đối tượng không thể thay đổi theo mặc định. Đây là nơi mà valuesđá quý rất hữu ích.

Nếu bạn đã quen thuộc với Structthư viện tiêu chuẩn , valuesthì về cơ bản gem cũng giống như vậy, ngoại trừ việc nó là bất biến theo mặc định.

Đây là một số mã ví dụ:

require 'values' # `Value.new` creates a new class, just like `Struct`Person = Value.new(:name, :age) # The `new` class method works just like `Struct`tom = Person.new('Tom', 28)puts tom.age #=> 28 # There is also the `with` class method, that creates an# object given a hashdane = Person.with(name: 'Dane', age: 42)puts dane.age #=> 42 # You can use the `with` instance method to create new objects# based existing objects, with some attributes changedben = tom.with(name: 'Ben')p ben #=> #<Person name="Ben", age=28>p tom #=> #<Person name="Tom", age=28> # Unlike `Struct`, objects do not have any mutating methods definedtom.name = 'Ben'#=> NoMethodError: undefined method `name=' for #<Person name="Tom", age=28>

Cũng giống như Structcác lớp, các Valuelớp này có thể có các phương thức tùy chỉnh:

Fungus = Value.new(:genus, :species, :common_name) do  def display_name    "#{common_name} (#{genus} #{species})"  endend f = Fungus.new('Amanita', 'muscaria', 'Fly agaric')puts f.display_name #=> Fly agaric (Amanita muscaria)

Không giống như Structcác lớp, các lớp này sẽ tạo ra lỗi nếu thiếu bất kỳ thuộc tính nào khi tạo. Đây là một điều tốt, vì nó cảnh báo bạn về những lỗi tiềm ẩn thay vì im lặng bỏ qua chúng.

Person = Value.new(:name, :age) Person.new('Tom') #=> ArgumentError: wrong number of arguments, 1 for 2Person.with(age: 28) #=> ArgumentError: Missing hash keys: [:name] (got keys [:age])

Các lớp này chỉ là bất biến nông, giống như freezephương thức tích hợp sẵn. Bản thân các đối tượng không thể thay đổi, nhưng các thuộc tính của chúng vẫn có thể thay đổi được.

tom = Person.new('Tom', 28)tom.name.upcase!p tom #=> #<Person name="TOM", age=28>

Toàn bộ viên ngọc chỉ có khoảng 100 dòng mã , vì vậy rất dễ hiểu về toàn bộ.

Đối với phần lớn các tình huống mà bạn sẽ sử dụng Struct, tôi nghĩ Valuecác lớp học là lựa chọn tốt hơn. Đối với những tình huống hiếm hoi mà bạn đang cố gắng đạt được từng giọt hiệu suất cuối cùng, Structvẫn là lựa chọn tốt hơn, ít nhất là trên MRI. Điều đó không có nghĩa là Valuecác lớp chậm - chúng có hiệu suất tương tự như bất kỳ lớp Ruby nào khác, nếu không muốn nói là tốt hơn do quá trình băm tích cực. Trong MRI, Structlớp được thực hiện theo một cách hiệu quả bất thường. Trong các triển khai khác, chẳng hạn như JRuby, có thể không có sự khác biệt về hiệu suất.

Nếu bạn không sử dụng Structcác lớp, bạn có thể tự hỏi tại sao và nơi bạn muốn sử dụng một trong hai lớp đó. Nguồn tốt nhất mà tôi có thể chỉ cho bạn là Giá trị của các Giá trị của Rich Hickey . Cuối cùng, nó tóm tắt tất cả những lợi ích của ngữ nghĩa giá trị , mà Rich giải thích chi tiết.

Các adamantiumGem - Tự động Recursive Freezing

Các adamantiumđá quý cung cấp đóng băng đệ quy tự động cho các lớp học của Ruby qua ice_nineđá quý.

require 'adamantium' class Person  include Adamantium   attr_reader :name, :age   def initialize(name, age)    @name = name    @age = age  end   def with_name(new_name)    transform do      @name = new_name    end  endend tom = Person.new('Tom', 28)dane = tom.with_name('Dane') p tom  #=> #<Person:0x007f90b182bb28 @name="Tom", @age=28 ...p dane #=> #<Person:0x007f90b0b28048 @name="Dane", @age=28 ...

Adamantium hoạt động bằng cách ghi đè newphương thức lớp. Sau khi một đối tượng đã được cấp phát và initializephương thức của nó đã được chạy, nó sẽ bị đóng băng bằng cách sử dụng ice_ninegem. Điều này có nghĩa là bạn có thể thay đổi đối tượng từ bên trong initialize, nhưng không bao giờ lặp lại.

Để tạo các đối tượng bất biến mới từ những đối tượng hiện có, có một transformphương pháp. Điều này hoạt động bằng cách tạo ra một bản sao có thể biến đổi, chạy một khối đột biến trên bản sao, sau đó đóng băng sâu bản sao đó trước khi trả lại. Bạn có thể xem một ví dụ về điều này trong with_namephương pháp trên.

Adamantium yêu cầu nhiều tấm boilerplate hơn valuesgem, nhưng nó thực hiện đóng băng đệ quy thích hợp. Nó cũng có chức năng tự động ghi nhớ và đóng băng các giá trị trả về của các phương thức.

Các animaGem - includable Value Semantics

Các animaviên ngọc cơ bản là một hỗn hợp của valuesđá quý và adamantiumđá quý.

require 'anima' class Person  include Anima.new(:name, :age)end tom = Person.new(name: 'Tom', age: 28)rhi = tom.with(name: 'Rhiannon') p tom #=> #<Person name="Tom" age=28>p rhi #=> #<Person name="Rhiannon" age=28>

Nó có tính ngắn gọn của valuesđá quý và sử dụng Adamantium để đóng băng đệ quy tự động.

Hãy coi đây là phiên bản có trọng lượng nặng của valuesviên đá quý. Nó có một vài tính năng hơn, nhưng nó cũng mang lại lăm đá quý như phụ thuộc: ice_nine, memoizable, abstract_type, adamantiumequalizer. Để so sánh, valuesgem không có phụ thuộc và được triển khai trong một tệp duy nhất với khoảng 100 dòng mã.

Các hamsterGem - Persistent Cấu trúc dữ liệu

Các hamsterđá quý cung cấp một tập các lớp cấu trúc dữ liệu liên tục. Các lớp học này thay thế bất biến cho các lớp học của Ruby tiêu chuẩn như Hash, Array, và Set. Chúng hoạt động theo kiểu tương tự như các viên ngọc khác - không thể sửa đổi các đối tượng, nhưng bạn có thể tạo các đối tượng mới dựa trên các đối tượng hiện có.

Làm việc với các giá trị không thay đổi thường đòi hỏi nhiều bản sao, giống như sao chép toàn bộ mảng chỉ để thêm một phần tử mới. Cấu trúc dữ liệu liên tục cung cấp hiệu suất tốt hơn cho các loại hoạt động này bằng cách giảm số lượng đối tượng cần được sao chép và sử dụng lại càng nhiều đối tượng càng tốt.

Ví dụ, nếu bạn muốn tạo một mảng được cố định từ một mảng đã được cố định hiện có, bạn sẽ phải làm như thế này trong Ruby đơn giản:

original = [1, 2, 3].freeze new_one = original.dup # makes a copynew_one << 4new_one.freeze p original #=> [1, 2, 3]p new_one  #=> [1, 2, 3, 4]

Với Hamster::Vector, điều này sẽ trông giống như:

require 'hamster' original = Hamster::Vector[1, 2, 3]new_one = original.add(4) p original #=> Hamster::Vector[1, 2, 3]p new_one  #=> Hamster::Vector[1, 2, 3, 4]

Trong Hamster::Vectorphiên bản, new_onecó thể không phải là một bản sao hoàn toàn của original. Bên trong, new_onegiá trị có thể chỉ giữ 4một tham chiếu cộng với original. Chia sẻ trạng thái bên trong theo cách này cải thiện cả tốc độ và mức sử dụng bộ nhớ, đặc biệt là đối với các đối tượng lớn. Tất cả điều này diễn ra tự động dưới mui xe, vì vậy bạn không cần phải suy nghĩ về nó.

Để có cái nhìn tổng quan về chủ đề này, tôi giới thiệu một bài nói chuyện Rich Hickey khác: Cấu trúc dữ liệu liên tục và tài liệu tham khảo được quản lý . Chuyển tiếp đến 23:49 để đến phần cụ thể về cấu trúc dữ liệu liên tục.

Đối tượng giá trị Virtus

Tôi muốn nhanh chóng đề cập đến virtusđá quý , mặc dù tôi khuyên không nên sử dụng nó. Nó có một số chức năng "đối tượng giá trị" hoạt động rất giống với valuesand animagems, nhưng với các tính năng bổ sung xung quanh xác thực kiểu và cưỡng chế.

require 'virtus' class Person  include Virtus.value_object   values do    attribute :name, String    attribute :age,  Integer  endend tom = Person.new(name: 'Tom', age: 28)sue = tom.with(name: 'Sue') p tom #=> #<Person name="Tom" age=28>p sue #=> #<Person name="Sue" age=28>

Về lý do tại sao tôi khuyên bạn không nên sử dụng nó, hãy để tôi trích dẫn tác giả của viên đá quý Piotr Solnica trong chủ đề reddit này :

Lý do tại sao tôi không còn quan tâm đến việc làm việc trên nền tảng công nghệ không phải là điều tôi có thể giải thích dễ dàng, nhưng tôi sẽ cố gắng.

[…]

[Nó] đã được tối ưu hóa cho một trường hợp sử dụng cụ thể là lưu trữ dữ liệu từ một biểu mẫu web để làm cho cuộc sống của chúng ta đơn giản hơn và chức năng này chỉ đơn giản là được đưa vào ORM

[…]

Tôi đã phạm phải một sai lầm mà trước đây đã từng mắc phải từ ActiveRecord.

[…]

Tôi đã mất một lúc để hiểu điều gì đang thực sự diễn ra. Virtus là viên ngọc mang lại di sản của DataMapper, mang lại di sản của… ActiveRecord. Đó là một quá trình dài để hiểu một số vấn đề cơ bản, khi tôi đã hiểu chúng, tôi bắt đầu làm việc trên các thư viện mới để giải quyết những vấn đề đó theo cách tốt hơn. Tôi càng làm việc nhiều hơn với những thư viện đó, tôi càng thấy rõ ràng rằng Virtus sẽ phải được thay đổi hoàn toàn và sẽ không còn phục vụ cùng mục đích nếu tôi muốn xây dựng nó theo cách mà tôi nghĩ là đúng.

Virtus đã cố gắng trở thành một con dao quân đội Thụy Sĩ phổ biến cho các cuộc cưỡng chế, như một hệ quả tự nhiên của việc được trích xuất từ ​​một ORM có nhiều điểm chung với ActiveRecord, nó đã cố gắng làm quá nhiều, với rất nhiều hành vi ngầm, các trường hợp cạnh kỳ lạ, hiệu suất các vấn đề và DSL phức tạp.

[…]

Hơn nữa, thuộc tính DSL với nhiều tùy chọn là một mô hình chống. Đó là những gì tôi đã học được theo thời gian. Và nó không kết thúc ở đây - thiếu an toàn kiểu thực tế là một vấn đề, Virtus có một chế độ nghiêm ngặt nhưng không thể làm cho nó đúng trong một thư viện được sử dụng trong nhiều bối cảnh khác nhau.

Sắp tới tiếp theo: Phong cách kỷ luật và chức năng

Bài viết này chỉ đề cập đến các tùy chọn thuộc loại nặng tay. Tất cả đều yêu cầu đá quý hoặc mã bổ sung.

Bài tiếp theo sẽ nói về cái mà tôi gọi là “phong cách chức năng” - sử dụng kỷ luật để tránh đột biến, thay vì thực thi tính bất biến. Nó không yêu cầu thêm đá quý và không cần thêm mã. Giữ nguyên!

5 hữu ích0 bình luận2.7k xemchia sẻ

Với SharePoint Framework, các nhà phát triển có thể sử dụng các khung như Angular, WebPack & Kendo UI để thiết kế SharePoint UI tùy chỉnh. Tìm hiểu con đường bạn nên đi. Vào tháng bảy, chúng tôi đã ở một ngã ba. Chúng tôi vừa kết thúc một mô-đun SharePoint On-Premises mới với Angular v1.4 và ngOffice UI Fabric. Mô-đun trước đó của chúng tôi là Angular v1.2 với UI Bootstrap. Chúng tôi biết rằng SharePoint Framework sắp ra mắt và thậm chí cuối cùng sẽ được đưa xuống On-Premise vào năm 2017. Ngoài ra, với tốc độ JavaScript di chuyển, về cơ bản chúng tôi cần phải làm mới hộp công cụ của mình ba tháng một lần.

Đã đến lúc phải thực hiện một chút nghiên cứu — và vì vậy chúng tôi đã làm.

Chọn một con đường

Nghiên cứu này đã đạt đến đỉnh cao trong việc viết Sách chuẩn bị cho Hộp công cụ của bạn cho Khuôn khổ SharePoint với Sách trắng về giao diện người dùng Angular, Webpack và Kendo , được xây dựng xung quanh bản trình diễn Đăng ký Hợp đồng (GitHub) này . Các công nghệ chúng tôi chọn chủ yếu tập trung vào những gì chúng tôi đã quen thuộc, nhưng cũng những gì chúng tôi biết sẽ được hỗ trợ trong SharePoint Framework. Chúng tôi đã kiểm tra kỹ với các ví dụ từ nhiều chuyên gia đã viết blog về trải nghiệm SharePoint Dev Kitchen của họ và đối chiếu với tất cả các video PnP SPFx .

Angular

Chúng tôi bắt đầu với Angular và Kendo UI bằng Gulp, nhưng quá trình xây dựng liên quan đến việc đóng gói vào CDN, vì vậy chúng tôi đã thêm WebPack.

Cuối cùng, thay vì nói chuyện trực tiếp với SharePoint hoặc sử dụng các thành phần Kendo UI DataSource (cũng hỗ trợ SharePoint REST), tôi muốn chúng tôi sử dụng pnp-js-core — một API thông thạo để nói chuyện với điểm cuối REST từ nhóm Office PnP.

Chúng tôi đã chuyển phiên bản của mình lên Angular v1.5 vì chúng tôi muốn ở vị trí tốt nhất để có thể "triển khai sản xuất" ngay hôm nay, nhưng vẫn ghi vào thông số kỹ thuật của thành phần sẽ là tiêu chuẩn trong Angular v2. Hơn nữa, SPFx-webparts sẽ chạy trong Ứng dụng di động SharePoint trong tương lai. Vì vậy, không cần phải làm thêm quá nhiều công việc một cách rõ ràng — chúng tôi đang xây dựng hướng tới tương lai nơi chúng tôi xây dựng và nó chạy trong trình duyệt và trên thiết bị di động.

PnP JS Core

Đối với PnP JS Core, API thông thạo là một niềm vui khi làm việc cùng và cách thực hiện phân phối khá kỳ diệu. Trong v1.0.3, thư viện cũng bắt đầu hỗ trợ NodeJS, có nghĩa là bạn có thể sử dụng cùng một mã JavaScript để tương tác với SharePoint từ cả trình duyệt và máy chủ. Viết cùng một đoạn mã chạy ở cả hai nơi là chén thánh mà chúng ta luôn hướng tới. Nếu JavaScript có thể chạy ở mọi nơi, thì các thư viện chúng ta muốn sử dụng sẽ có thể chạy ở mọi nơi.

WebPack

Khi chúng tôi tìm hiểu sâu hơn về điều kỳ diệu đó là WebPack , điều kỳ diệu của nó đã được hé mở. Trong video giới thiệu nhỏ này mà chúng tôi đã quay cho Đăng ký hợp đồng , bạn có thể nhận thấy WebPack đưa mã vào trình duyệt nhanh như thế nào — ứng dụng đã sẵn sàng trước khi thanh bộ Office 365 xuất hiện. Đây là một tác dụng phụ của việc tách mã. WebPack không chỉ đơn thuần liên hệ và hủy xác minh tệp JS, nó còn phóng các mô-đun JavaScript vào trình duyệt như một khẩu súng ngắn — tất cả cùng một lúc. WebPack gần như loại bỏ sự cần thiết của Gulp trong quá trình này. Gulp vẫn cần thiết để bắt đầu các tác vụ khác nhau, nhưng WebPack thực hiện công việc bên dưới và nó thực sự hoạt động tốt.

TypeScript

Chúng tôi đã tranh luận rất nhiều về TypeScript. Nó sẽ làm cho IntelliSense và kiểm tra mã tốt hơn, nhưng chúng tôi quyết định loại bỏ nó. Đáng lẽ ra phải học thêm "một điều nữa", và danh sách đã dài ra. Hãy xem mã chúng tôi đã viết cho sổ đăng ký hợp đồng (GitHub) và cho chúng tôi biết nếu chúng tôi đã lựa chọn đúng.

Giao diện người dùng Kendo

Tôi cũng muốn nói về Kendo UI . Tôi đã không sử dụng Kendo UI trước dự án này. Đồng nghiệp của tôi và đồng tác giả của whitepaper này, Bart Bouwhuis, là một người hâm mộ lớn và anh ấy liên tục cho tôi thấy những đặc điểm thú vị. Sách trắng không phải là quảng cáo cho Tiến bộ (trước đây là Telerik), nhưng tôi cũng nghĩ rằng chúng ta không thực sự nói về giao diện người dùng Kendo nhiều như chúng ta nên làm.

Cảm giác của tôi là các thành phần Kendo UI đã thực sự trưởng thành — trong một số lĩnh vực cạnh tranh hoặc vượt quá UI Bootstrap. Dễ dàng thêm các thành phần như Grid , WindowPDF export . Chúng đã hỗ trợ chủ đề Office 365 , vì vậy chúng không có vẻ gì là lạc hậu.

Telerik hỗ trợ Angular v1 và họ vừa phát hành bản xem trước dành cho nhà phát triển cho Angular 2 . Cuối cùng, chúng tôi đã dành rất ít thời gian để làm cho các thành phần hoạt động với chúng tôi — trong hầu hết các trường hợp, chúng tôi đã tìm kiếm ví dụ trên Telerik Docs và nó chỉ hoạt động! Một điều may mắn nữa là chúng tôi không bao giờ cần phải chỉnh sửa CSS để khắc phục một số vấn đề về kiểu dáng. Đó thực sự là một vấn đề khá nhức nhối với UI Bootstrap hoặc ngOfficeUIFnai.

Bản xem trước dành cho nhà phát triển SharePoint Framework (SPFx)

Mọi thứ đang chuyển động nhanh chóng. Bản xem trước dành cho nhà phát triển SPFx được đưa ra trong quá trình viết whitepaper. Nhớ chuyến tàu đó chứ? Hóa ra nó đến rất nhanh. Chúng tôi thích tốc độ chạy của nhóm SharePoint. Nhưng nó có nghĩa là chúng tôi có một số lưu ý để thêm vào.

Thứ nhất, whitepaper không chỉ về SPFx. Đó là về SharePoint như một nền tảng với AngularJS và WebPack, đồng thời có những phần đó sẵn sàng và được căn chỉnh cho SPFx. Đó là về một bộ công cụ cốt lõi ổn định hoạt động tốt cùng nhau. Đó là về một bộ công cụ chạy ngày nay trên SharePoint 2016, SharePoint 2013 và SharePoint Online. Bạn đã có thể sử dụng chúng mà không cần phải đợi SPFx.

Thứ hai, với SPFx thậm chí còn có nhiều cơ hội hơn. Chúng tôi sẽ hỗ trợ tốt hơn cho các chế độ Angular và SPA — hiện tại cả hai kịch bản đều chưa được phát hành. Vì vậy, câu chuyện sẽ phát triển và trở nên tuyệt vời hơn. Bản demo đăng ký hợp đồng có thể chạy ở chế độ phần mềm web SPFx — trong trường hợp đó, mã để khởi chạy ứng dụng và thiết lập các danh sách khác nhau sẽ đi vào bảng thuộc tính phần web. Chỉ người đóng góp mới có quyền truy cập vào việc tạo danh sách.

Cách chúng tôi quyết định quản lý dòng chảy liên tục này là xuất bản bản cập nhật blog khi SPFx chính thức được phát hành để lấp đầy “khoảng trống” —các điều chưa biết về thời điểm xuất bản whitepaper. Vì vậy, hãy theo dõi bản cập nhật như vậy, có thể là sau Microsoft Ignite. Chúng tôi cũng có một loạt các ý tưởng điên rồ được liệt kê cho Sổ đăng ký Hợp đồng. Vì vậy, nếu bạn muốn có được bàn tay của bạn bẩn và đi, chúng tôi đang thực hiện các yêu cầu kéo!

Tham gia ngay hôm nay

Thời gian để tham gia luôn là bây giờ (hoặc ngay khi bạn có thể). Ở đây, chúng tôi trình bày hai tháng làm việc thể hiện nỗ lực hết mình của chúng tôi nhằm thúc đẩy các công nghệ web hiện đại và SharePoint như một nền tảng.

3 hữu ích0 bình luận6.2k xemchia sẻ

tldr; tìm hiểu cách sử dụng bảng điều khiển dành cho nhà phát triển và các lệnh javascript cơ bản (cho, do… trong khi, nếu… sau đó, các biến) để tự động hóa theo gui và tăng cường thử nghiệm web kỹ thuật tương tác của bạn.

trước đây tôi chỉ sử dụng bảng điều khiển javascript trong các công cụ dành cho nhà phát triển chrome để xem các lỗi javascript. nhưng tôi đã đọc tài liệu về bảng điều khiển javascript và nhận ra rằng tôi có thể ra lệnh và xem các đối tượng. tôi dần dần nhận ra rằng tôi có thể sử dụng điều này để giúp tôi kiểm tra tốt hơn.

chơi với các trò chơi javascript để học

và sau đó tôi bắt đầu chơi với các trò chơi javascript… ý tôi là 'chơi với' chứ không phải 'chơi'. về cơ bản là 'hack' các trò chơi để có được mạng sống vô hạn. tôi bắt đầu làm điều đó bằng cách hiểu mã, chặn mã nguồn trong proxy và thay đổi nó. tôi đã viết blog về ' trò chơi hack '.

tất cả những điều này tôi đã làm bởi vì tôi đã học đủ javascript để trở nên nguy hiểm và cách viết nó trên bảng điều khiển.

nhưng người thử nghiệm 'làm việc' với các ứng dụng

với tư cách là người thử nghiệm, tôi muốn tương tác với các ứng dụng, vì vậy tôi thực sự muốn học cách kiểm tra các ứng dụng trong điều kiện và khám phá nhiều điều kiện hơn.

vì vậy, thay vì phải nhấp vào nút 'tôi muốn một khẩu hiệu' trong "bộ tổ chức thử nghiệm ác " của tôi , mọi lúc. thay vào đó, tôi có thể tạo hàng nghìn khẩu hiệu từ bảng điều khiển và xem lại chúng ở đó.

ví dụ

for(var x=0;x<100;x++){console.log("-" + random_sentence());}

hoặc tôi có thể chỉnh sửa mã một chút để tạo ra hàng nghìn bản thuyết minh của một mẫu cụ thể. rất hữu ích khi thử nghiệm thứ gì đó được tạo ngẫu nhiên.

bạn có thể thử cho mình trên sloganizer , mã khá đơn giản của nó, xem liệu bạn có thể tìm ra cách tạo 1000 bản thuyết minh của một câu cụ thể hay không.

nếu tôi đang thử nghiệm ứng dụng todomvc , thì tôi sẽ muốn tạo nhiều dữ liệu rất dễ dàng, thay vì phải tạo một loạt các mục cần làm trong ứng dụng này một cách thủ công và chậm chạp. tôi có thể viết một lượng nhỏ mã và tạo 100 mã trong vòng chưa đầy một giây. hoặc 1000 trong vòng chưa đầy một giây. hoặc thực sự thúc đẩy ứng dụng và xem nó có thể đối phó với bao nhiêu ứng dụng.

nhưng tôi cũng có thể điều khiển chúng - giả sử chuyển đổi một nửa trong số chúng. và tôi cũng có thể xóa chúng.

hãy thử nó cho chính mình:

  • xem bạn có thể tạo các việc cần làm tự động không

  • xóa việc cần làm

  • sửa đổi chúng

  • chuyển đổi chúng để được hoàn thành

nếu bạn có thể làm như trên thì bạn đã triển khai các chức năng crud (tạo, đọc, cập nhật, xóa) cần thiết để tăng cường khả năng khám phá và thử nghiệm tương tác của bạn đối với ứng dụng và bây giờ bạn sẽ có thể kiểm tra toàn bộ các kết hợp và điều kiện mới điều đó sẽ khó kiểm tra hơn.

từ bảng điều khiển

và tất cả những điều này chúng ta có thể làm từ bảng điều khiển javascript.

với một số lệnh javascript cơ bản:

chúng ta cũng cần học cách tìm các đường nối trong ứng dụng javascript bằng cách đọc nguồn và sử dụng chức năng 'tìm'.

học cách sử dụng bảng điều khiển

bảng điều khiển là một công cụ mà tôi hầu như không bao giờ sử dụng trong thử nghiệm của mình. tôi chủ yếu làm việc với các ứng dụng web ở cấp độ gui hoặc http.

bằng cách sử dụng bảng điều khiển, chúng tôi có thể làm việc trong gui mà không cần phải rời khỏi trình duyệt và thử nghiệm ở cấp độ mới với ứng dụng của chúng tôi.

điều này sẽ càng trở nên quan trọng hơn khi chúng ta phải làm việc với nhiều ứng dụng trang đơn hơn và các ứng dụng sử dụng khung và mã javascript mvc sử dụng dom bóng.

nếu bạn đã học html và css và bạn biết cách sử dụng proxy, thì bạn có thể đẩy thử nghiệm web kỹ thuật của mình xuống cấp javascript và học cách tận dụng bảng điều khiển trong quá trình thử nghiệm của mình.

cách kiểm tra ứng dụng javascript từ bảng điều khiển công cụ dành cho nhà phát triển chrome trên vimeo.

bạn có thể xem video này trên youtub e nếu bạn thích.

Ghi chú:

phần “kiểm tra javascript từ bảng điều khiển công cụ dành cho nhà phát triển trình duyệt” trong khóa học “kiểm tra web kỹ thuật 101” của tôi hướng dẫn bạn cách thực hiện việc này. phần này có hơn một giờ video giải thích cách kiểm tra các ứng dụng javascript từ bảng điều khiển trình duyệt. kiểm tra khóa học và chỉ với $ 10, bạn có thể tìm hiểu về các công cụ dành cho nhà phát triển, proxy, thử nghiệm nghỉ ngơi, thử nghiệm web di động và hơn thế nữa.

15 hữu ích0 bình luận3.5k xemchia sẻ

một cách mạnh mẽ để gỡ lỗi (đặc biệt là các mẫu) trong góc 1 là json pipe (hoặc bộ lọc) có thể được sử dụng trong một mẫu. đường ống vẫn tồn tại nguyên bản trong góc 2. đây là cách bạn có thể nhập và sử dụng nó.

đặc biệt là khi bạn phải gỡ lỗi các mẫu góc của mình, nó đặc biệt hữu ích trong góc 1 để sử dụng bộ lọc json.

<h1>some template</h1><pre>{{ myobj | json }}</pre>

kết quả là bạn có được một biểu diễn json được định dạng độc đáo cho đối tượng javascript kết hợp dữ liệu của bạn.

sử dụng jsonpipe trong góc 2

điều tương tự đối với góc 2, cũng có đối tượng jsonpipe tích hợp.

để sử dụng nó, bạn phải nhập gói commonmodule từ @angular/common gói vào mô-đun của riêng bạn.

import { commonmodule } from '@angular/common';  @ngmodule({    ...    imports: [ commonmodule ]    ...})

thì bạn có thể bắt đầu sử dụng nó trong mẫu của mình, giống như bạn đã làm trong góc 1.

@component({    selector: 'my-app',    template: `      <pre>{{ myobj | json }}</pre>    `})export class myappcomponent {    myobj: any;     constructor() {        this.myobj = {            name: 'juri',            website: 'http://juristr.com',            twitter: '@juristr'        };    }}

dễ dàng, phải không?

thử nó cho mình

đây là một plunker để chơi với: https://plnkr.co/edit/za3ogwlgwg0ralyz1ivj?p=preview

1 hữu ích0 bình luận3.1k xemchia sẻ

TL; DR Angular 2 giới thiệu một hệ thống phát hiện thay đổi được sáng tạo lại giúp giảm các chu kỳ thông báo theo hướng một chiều. Ngoài ra, tính năng phát hiện thay đổi giờ đây có thể được kiểm soát và tinh chỉnh bởi các nhà phát triển để tận dụng tối đa hiệu suất của khung.

Giới thiệu về Phát hiện Thay đổi

Angular 2 cuối cùng đã được phát hành. Bạn có thể đã nghe nói về một số thay đổi do va chạm phiên bản lớn: nó đã được viết lại hoàn toàn, TypeScript được chọn làm ngôn ngữ lựa chọn, các biểu mẫu được phát minh lại, RxJS, một bộ định tuyến hoàn toàn mới, v.v. Theo ý kiến ​​của tôi, hầu hết điều đáng giá là việc thiết kế lại hệ thống phát hiện thay đổi cốt lõi. Như bạn có thể nhớ, hiệu suất vòng lặp thông báo của AngularJS (hay còn gọi là Angular 1) có vấn đề. Bây giờ thì không.

Tại sao chúng ta cần phát hiện thay đổi?

Quan tâm làm gì? Nói chung, sức mạnh của các khung JavaScript hiện đại hoạt động giống như sau: một sự kiện thay đổi trong mô hình và buộc phải thay đổi giao diện người dùng. Đây là phát hiện thay đổi, hệ thống giám sát các sự kiện và hành động trên chúng. Một cái gì đó phải kích hoạt sự lan truyền này đến chế độ xem. Như đã đề cập trước đây, trong Angular 1, chúng tôi có các vòng lặp thông báo kiểm tra mọi tham chiếu đơn lẻ được đặt để theo dõi các thay đổi giá trị. Khi Angular phát hiện ra rằng mọi thứ đều ổn định (không có vòng lặp vô hạn, v.v.), nó đã tuyên truyền các thay đổi đối với chế độ xem. Mặc dù điều này không hiệu quả, nhưng nó đã hoạt động trong một thời gian dài. Ngoài ra, vấn đề là theo dõi các sự kiện không đồng bộ. Bạn cũng có thể sử dụng $scope.$apply(...)nếu bạn đã làm việc với Angular 1. Để hiểu tại sao nó lại cần thiết, chúng ta hãy bắt đầu lại từ đầu.

Cách hoạt động của Javascript

Thời gian chạy JavaScript hoạt động trên một công cụ phân luồng duy nhất. Bạn có thể đã nghe nói về ngăn xếp (có thể từ các ngôn ngữ lập trình khác). Hãy lấy đoạn mã dưới đây:

console.log('Hey')setTimeout(() => {   console.log('Hello from timeout!')}, 1000);console.log('Hi')

Chúng tôi sẽ thấy điều này trong một bảng điều khiển dưới dạng:

HeyHiHello from timeout!

Hơn nữa, không có gì bị chặn trong khoảng thời gian chờ một giây. Vậy công cụ JS sẽ thực hiện điều này như thế nào với một luồng duy nhất?

Mã đồng bộ

Hãy đi từng bước một. Nếu bạn có mã như thế này:

console.log('1')console.log('2')console.log('3')

mọi lệnh sẽ được đưa vào ngăn xếp và sẽ chạy từng lệnh một. Không có khả năng nhìn thấy 3 trước 2 hoặc 1. Vì vậy, chúng tôi sẽ kết thúc với những điều sau:

123

Mỗi lần. Mọi nơi.

Mã không đồng bộ

Nhưng hãy quay lại thời gian chờ:

console.log('1')setTimeout(() => {  console.log('2')}, 0)console.log('3')

Điều gì xảy ra bây giờ? Trên ngăn xếp, chúng ta sẽ có:

console.logsetTimeoutconsole.log

Bí quyết ở đây là cách thức setTimeouthoạt động và nó thực sự là gì. Có, nó sẽ được gọi như một hành động đồng bộ bình thường, nhưng tất cả những gì mà công cụ JS làm là đưa bánh xe cho một thứ khác. Có một loạt các API trình duyệt không phải là một phần của quy trình đơn luồng này. Và có một thứ gọi là vòng lặp sự kiện. Vòng lặp sự kiện này lần lượt đi qua các hướng dẫn ngăn xếp và nếu nó trống, thì nó sẽ chuyển đến hàng đợi gọi lại . Tham chiếu đến setTimeoutmã là ở đó. Sau khi gọi lại xong, mã sẽ chuyển đến ngăn xếp.

Nó có nghĩa là gì? Hai điều:

  • Mọi thứ bên trong lệnh gọi lại không đồng bộ (như trong setTimeout) sẽ được chạy sau bất kỳ mã đồng bộ nào khác; đây là lý do tại sao hack setTimeout(() => {}, 0)hoạt động như vậy .

  • Chúng tôi không có cách nào để đảm bảo 1000ms chính xác là 1000ms (nhưng chúng tôi biết rằng nó ít nhất là 1000ms).

Để hiểu đầy đủ về vòng lặp sự kiện và những gì đang diễn ra trong trình duyệt, tôi khuyến khích bạn xem qua bài nói chuyện này của Philip Roberts .

Cách các khu vực liên quan đến phát hiện thay đổi

Làm thế nào để tất cả những điều này liên quan đến Angular và phát hiện thay đổi? Theo dõi các đối tượng với mã đồng bộ là khá dễ dàng. Tuy nhiên, khi nói đến mã không đồng bộ, mọi thứ trở nên phức tạp. Đó là bởi vì góc 1 buộc chúng tôi phải sử dụng $scope.$apply(...)mỗi lần một hành động không đồng bộ đã được thực hiện hoặc sử dụng các đường góc làm những hành động không đồng bộ: $timeout, $http, và vân vân. Vấn đề là, nếu một cái gì đó được thực hiện bên ngoài bộ điều khiển (thậm chí là một thay đổi hoàn toàn hợp lệ đối với đối tượng tham chiếu), Angular không biết về nó, vì vậy nó không kích hoạt bất kỳ sự kiện nào để phản ánh các thay đổi đối với giao diện người dùng.

Mặt khác, bây giờ chúng ta có Angular 2. Nó đã loại bỏ tất cả những thứ được kết nối với các chu kỳ tiêu hóa và bây giờ sử dụng Zones . Các khu vực có thể theo dõi ngữ cảnh của các hành động không đồng bộ bằng cách vá chúng (tức là ghi đè chúng bằng mã riêng của nó), sau đó gọi hành động mong muốn nhưng kèm theo một số thông tin bổ sung. Thông tin bổ sung này là bối cảnh. Bằng cách này, Angular sẽ biết hành động không đồng bộ được gọi từ thành phần nào.

Chiến thắng lớn của phương pháp này là chúng ta có thể sử dụng các API của trình duyệt một cách nguyên bản và Angular sẽ biết điều gì đang xảy ra mà không buộc chúng ta phải thông báo thủ công về việc thay đổi đã xảy ra. Hạn chế là Zones ghi đè các hành động không đồng bộ, đây là một loại giải pháp khó hiểu và có thể ảnh hưởng đến mã (hiện có) khác nếu chúng tôi không chỉ dựa vào Angular trong ứng dụng.

Nhưng chính xác thì Angular được thông báo về sự thay đổi như thế nào? Angular sử dụng phiên bản Zone được gọi của riêng nó NgZone, nó chuyển tiếp các hành động không đồng bộ đã hoàn thành với onTurnDonesự kiện. Phát hiện thay đổi góc đợi sự kiện thực hiện phát hiện thay đổi và kiểm tra những gì cần được cập nhật trong giao diện người dùng. Đó là hành vi cốt lõi.

Tận dụng tính năng phát hiện thay đổi trong ứng dụng của bạn

Mọi thứ được mô tả ở trên đang diễn ra dưới mui xe. Điều quan trọng không kém là chúng ta có thể tận dụng nó như thế nào. Không giống như Angular 1, Angular 2 cho chúng ta khả năng kiểm soát phát hiện thay đổi. Tuy nhiên, nhóm Angular tuyên bố rằng ngay cả khi không có bất kỳ điều chỉnh hiệu suất nào, nó nhanh hơn 3 đến 10 lần so với trước đó và đối với hầu hết các ứng dụng, điều này sẽ đủ nhanh. Nhưng nó có thể nhanh hơn nhiều. Hãy xem một ví dụ.

  <head>    <base href="." />    <title>angular2 playground</title>    <link rel="stylesheet" href="style.css" />    <script src="https://unpkg.com/zone.js@0.6.21/dist/zone.js"></script>    <script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>    <script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>    <script src="https://unpkg.com/typescript@1.8.10/lib/typescript.js"></script>    <script src="config.js"></script>    <script>    System.import('app')      .catch(console.error.bind(console));  </script>  </head>   <body>    <my-app>      loading...    </my-app>  </body> </html>

Đây là một vấn đề rất điển hình: hiển thị một danh sách. Có một thành phần chứa danh sách các thành phần khác có một số dữ liệu đầu vào. Nói chung, chúng ta có một vùng chứa với dữ liệu và một thành phần câm chỉ để hiển thị một mục danh sách duy nhất. Không có gì lạ mắt ở đây, chỉ là cái và ngOnChange. Những gì đang được thực hiện ở đây? ngOnChangephản ứng trên mọi thay đổi đầu vào và getter thêm ghi nhật ký bổ sung mỗi lần rowDatađược tìm nạp. Lưu ý rằng chúng tôi không sử dụng nó ở bất kỳ đâu bên ngoài mẫu.

Điều này có nghĩa là getter được kích hoạt bởi chính Angular. Và đoán xem điều gì sẽ xảy ra? Chúng tôi có một thay đổi duy nhất trên đầu vào, nhưng có hàng trăm nhật ký getter ở đó.

Tại sao vậy?

Angular được thông báo về sự thay đổi từ một số thành phần và phải kiểm tra xem điều đó ảnh hưởng như thế nào đến trạng thái hiện tại, vì vậy nó sẽ kiểm tra tất cả các giá trị cho sự thay đổi. Trên thực tế, nhóm cho biết họ có thể thực hiện hàng nghìn lần kiểm tra như vậy trong mili giây, nhưng nó vẫn lãng phí thời gian và thậm chí có thể gây hại cho ứng dụng dựa trên dữ liệu lớn của chúng tôi.

Tính bất biến

Điều thú vị về hệ thống phát hiện thay đổi mới là giờ đây chúng ta có thể điều chỉnh nó. Hãy tạm dừng Angular và xem xét đoạn mã sau:

const users = [{  name: 'John',  age: 27}, {  name: 'Anna',  age: 23}] users.push({  name: 'Max',  age: 30})

Điều quan trọng nhất ở đây là constkhai báo. Nếu userslà hằng số, chúng ta có thể sửa đổi nó như thế nào? Đó là cách JavaScript hoạt động! Điều này constngăn chúng tôi sửa đổi một tham chiếu đến đối tượng cụ thể trong JavaScript. Những gì pushphương thức Arraythực sự đang làm là thêm một đối tượng khác vào mảng hiện có (không có thay đổi tham chiếu). Hãy đi đến một ví dụ rất điển hình khác:

const user = {  name: 'Max',  age: 30} user.age = 31

Điều tương tự cũng được áp dụng. Mặc dù chúng ta không thể sửa đổi toàn bộ đối tượng để biến nó thành một đối tượng khác (thay đổi tham chiếu), chúng ta vẫn có thể thay đổi một phần của đối tượng!

Đây là lý do tại sao các kiểm tra mà chúng ta đã thảo luận trước đây không tốt như vậy. Nếu bạn muốn kiểm tra xem đối tượng có giống như trước đây hay không, bạn phải kiểm tra sâu tất cả các thuộc tính của nó . Nó không hiệu quả.

Làm thế nào chúng ta có thể buộc đối tượng phải là đối tượng mới với thuộc tính đã thay đổi? Nó thực sự khá dễ dàng với đề xuất thuộc tính trải rộng Đối tượng ECMAScript mới :

const user = {  name: 'Max',  age: 30} const modifiedUser = { ...user, age: 31 }

Thay đổi chiến lược phát hiện

Phần tốt của tất cả những điều này là bây giờ chúng ta có thể nói với Angular rằng chúng ta biết những gì chúng ta đang làm . Để thay đổi hành vi phát hiện sự thay đổi, chúng ta có thể sử dụng ChangeDetectionStrategyAPI, trong đó có một giá trị rất thú vị: OnPush. Nó làm cho một thành phần được áp dụng chiến lược này chỉ nhìn vào các giá trị bên trong khi tham chiếu trên đầu vào thay đổi hoặc một số sự kiện đã được kích hoạt khỏi thành phần.

Hãy thêm OnPushchiến lược vào ví dụ trước của chúng tôi:

import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; @Component({  selector: 'row',  template: `    <pre></pre>  `,  changeDetection: ChangeDetectionStrategy.OnPush})export class RowComponent {  ...}

Bạn có thể thử đoạn mã dưới đây trên Plunker và xem sự khác biệt.

<!DOCTYPE html><html>   <head>    <base href="." />    <title>angular2 playground</title>    <link rel="stylesheet" href="style.css" />    <script src="https://unpkg.com/zone.js@0.6.21/dist/zone.js"></script>    <script src="https://unpkg.com/reflect-metadata@0.1.3/Reflect.js"></script>    <script src="https://unpkg.com/systemjs@0.19.31/dist/system.js"></script>    <script src="https://unpkg.com/typescript@1.8.10/lib/typescript.js"></script>    <script src="config.js"></script>    <script>    System.import('app')      .catch(console.error.bind(console));  </script>  </head>   <body>    <my-app>      loading...    </my-app>  </body> </html>

Cải tiến lớn là giờ đây chỉ có một cuộc gọi nhận cho một thay đổi! Chúng tôi không cần thêm gì nữa vì dữ liệu đầu vào của chúng tôi là các chuỗi đang được thay đổi, do đó tham chiếu về đầu vào sẽ thay đổi. Tham chiếu cho phần còn lại của các thành phần không thay đổi, vì vậy Angular thậm chí không nhìn vào nó.

Cấu trúc ứng dụng

Làm cách nào để chúng tôi có thể xây dựng một ứng dụng hoạt động hiệu quả? Với Angular 2, nó thực sự khá dễ dàng. Như trong tất cả các khung công tác thành phần ngày nay, bạn nên có các thành phần thông minh và ngu ngốc. Các thành phần câm, vốn chỉ dùng để hiển thị dữ liệu từ đầu vào hoặc xử lý các sự kiện của người dùng, là những tình nguyện viên lý tưởng để có OnPushchiến lược. Các thành phần thông minh đôi khi sẽ yêu cầu bạn theo dõi nhiều thứ hơn đầu vào và các sự kiện, vì vậy hãy cẩn thận với việc thiết lập OnPushchiến lược ở đó.

Bên cạnh: Sử dụng Angular 2 với Auth0

Auth0 phát hành Mã thông báo web JSON trên mỗi lần đăng nhập cho người dùng của bạn. Điều đó có nghĩa là bạn có thể có một cơ sở hạ tầng nhận dạng vững chắc, bao gồm đăng nhập một lần, quản lý người dùng, hỗ trợ cho mạng xã hội (Facebook, Github, Twitter, v.v.), doanh nghiệp (Active Directory, LDAP, SAML, v.v.) và cơ sở dữ liệu của riêng bạn của người dùng chỉ với một vài dòng mã.

Bạn có thể thêm Auth0 vào ứng dụng Angular 2 rất dễ dàng. Chỉ có một số bước đơn giản:

Bước 0: Đăng ký Auth0 và định cấu hình

Nếu bạn chưa có bất kỳ tài khoản Auth0 nào, hãy đăng ký một tài khoản ngay bây giờ để làm theo các bước khác.

Bước 1: Thêm Auth0lock vào ứng dụng của bạn

Khóa là tiện ích hộp đăng nhập tuyệt đẹp (và hoàn toàn có thể tùy chỉnh) đi kèm với Auth0. Tập lệnh cho nó có thể được đưa vào từ liên kết CDN hoặc bằng npm.

Lưu ý: Nếu bạn sử dụng npm để tải Auth0Lock, bạn sẽ cần đưa nó vào bước xây dựng của mình.

   <!-- src/client/index.html -->   ...   <!-- Auth0 Lock script -->  <script src=“https://cdn.auth0.com/js/lock/10.0/lock.min.js"></script>   <!-- Setting the right viewport -->  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />   ...

Bước 2: Thêm dịch vụ xác thực

Tốt nhất bạn nên thiết lập một dịch vụ có thể tiêm để xác thực có thể được sử dụng trên toàn ứng dụng.

Với Auth0, chúng tôi có quyền truy cập vào hồ sơ của người dùng và JWT trong lệnh lock.ongọi lại nơi chúng tôi lắng nghe authenticatedsự kiện được kích hoạt khi người dùng đăng nhập thành công và các mục này có thể được lưu trong bộ nhớ cục bộ để sử dụng sau này.

// src/client/shared/auth.service.ts import {Injectable, NgZone} from 'angular2/core';import {Router} from 'angular2/router';import {AuthHttp, tokenNotExpired} from 'angular2-jwt'; // Avoid name not found warningsdeclare var Auth0Lock: any; @Injectable()export class AuthService {  lock = new Auth0Lock('YOUR_AUTH0_CLIENT_ID', 'YOUR_AUTH0_DOMAIN');  refreshSubscription: any;  user: Object;  zoneImpl: NgZone;   constructor(private authHttp: AuthHttp, zone: NgZone, private router: Router) {    this.zoneImpl = zone;    this.user = JSON.parse(localStorage.getItem('profile'));     // Add callback for lock `authenticated` event    var self = this;    this.lock.on("authenticated", authResult => {      self.lock.getProfile(authResult.idToken, (error, profile) => {         if (error) {          // handle error          return;        }         // If authentication is successful, save the items        // in local storage        localStorage.setItem('profile', JSON.stringify(profile));        localStorage.setItem('id_token', authResult.idToken);        self.zoneImpl.run(() => self.user = profile);      });    });  }   public authenticated() {    // Check if there's an unexpired JWT    return tokenNotExpired();  }   public login() {    // Show the Auth0 Lock widget    this.lock.show();  }   public logout() {    localStorage.removeItem('profile');    localStorage.removeItem('id_token');    this.zoneImpl.run(() => this.user = null);    this.router.navigate(['Home']);  }}

Bước 3: Thêm Trình xử lý nhấp chuột để đăng nhập

Để có thể sử dụng phương thức "Đăng nhập" và "Đăng xuất", chúng ta cần đưa dịch vụ Auth vào app.components.tstệp.

 <!-- src/client/app.components.ts -->import { Component } from '@angular/core';import { AuthService } from './auth.service'; ...

Trong NgModule gốc của bạn, hãy khai báo nhà cung cấp dịch vụ, như được hiển thị trong đoạn mã sau.

 <!-- src/client/app.module.ts --> ...import { AuthService } from './auth.service'; @NgModule({  imports: [    BrowserModule,    FormsModule,    routing,    HttpModule  ],  declarations: [    AppComponent  ],  providers: [    AUTH_PROVIDERS,    AuthService  ],  bootstrap: [AppComponent]})export class AppModule { }

Bây giờ, chúng tôi có thể sử dụng các phương pháp từ dịch vụ xác thực của chúng tôi trong bất kỳ thành phần nào của chúng tôi, có nghĩa là chúng tôi có thể dễ dàng thêm trình xử lý nhấp chuột vào nút "Đăng nhập" và "Đăng xuất".

  <!-- src/client/app.component.ts -->   ...   <button (click)="authService.login()" *ngIf="!authService.authenticated()">Log In</button>  <button (click)="authService.logout()" *ngIf="authService.authenticated()">Log Out</button>   ...

Sau khi người dùng đăng nhập, Mã thông báo web JSON sẽ được lưu cho họ trong bộ nhớ cục bộ. JWT này sau đó có thể được sử dụng để thực hiện các yêu cầu HTTP đã xác thực tới một API.

Bước 5: Thực hiện các yêu cầu HTTP đã xác thực

Với anuglar2-jwt , chúng tôi có thể tự động gửi các JWT của mình trong các yêu cầu HTTP. Để làm như vậy, chúng ta cần phải tiêm và sử dụng AuthHttp.

// src/client/ping/ping.component.ts import {Component} from 'angular2/core';import {Http} from 'angular2/http'; import {AuthHttp} from 'angular2-jwt';import {Auth} from './auth.service';import 'rxjs/add/operator/map'; @Component({  selector: 'ping',  template: `    <h1>Send a Ping to the Server</h1>    <button class="btn btn-primary" (click)="securedPing()" *ngIf="auth.authenticated()">Secured Ping</button>    <h2></h2>  `})export class Ping {  API_URL: string = 'http://localhost:3001';  message: string;   constructor(private http: Http, private authHttp: AuthHttp, private auth: Auth) {}   securedPing() {    this.authHttp.get(`${this.API_URL}/secured/ping`)      .map(res => res.json())      .subscribe(        data => this.message= data.text,        error => this.message = error._body      );  }}

Bước 5: Đã xong!

Đó là tất cả những gì cần làm để thêm xác thực vào ứng dụng Angular 2 của bạn với Auth0!

Kết luận

Ưu điểm về hiệu suất

Một trong những lợi thế lớn của việc sử dụng tính năng phát hiện thay đổi chặt chẽ hơn là tăng hiệu suất. Angular được sử dụng cho các ứng dụng lớn có thể xử lý nhiều dữ liệu động. Nhóm Angular đã cung cấp cho nhà phát triển các công cụ cần thiết để tinh chỉnh và cải thiện hiệu suất ngay từ đầu. Theo mặc định, mọi thay đổi sẽ được phản ánh trên giao diện người dùng, vì Angular sẽ xử lý điều đó, nhưng giá là hiệu suất thấp hơn. Mã bất biến hoặc mã phản ứng khó viết hơn nhưng dễ bảo trì và lập luận hơn. Sự lựa chọn là của bạn.

Cuối cùng thì Angular có thể được tinh chỉnh

Điều tốt là chúng tôi có quyền lựa chọn với Angular 2. Trong Angular 1, không thể thoát khỏi chu trình tiêu hóa. Ở một số điểm, việc sử dụng React hoặc một thư viện khác để kết xuất giao diện người dùng thay vì các mẫu Angular là một điều thuận lợi, vì nó quá chậm khi xử lý một lượng lớn dữ liệu động. Bây giờ, bạn có một giải pháp hoàn chỉnh với nhiều quyền kiểm soát hơn đối với hành vi nội bộ. Điều này, kết hợp với những thay đổi khác được thực hiện cho Angular 2, làm cho đường cong học tập của khung công tác dốc hơn nhưng đáng giá.

20 hữu ích0 bình luận15k xemchia sẻ

Trong một trong những dự án cuối cùng, tôi cần một thành phần có thể tái sử dụng được chia sẻ, thành phần này cần được mở rộng với nội dung hoặc chức năng bổ sung bởi chế độ xem người sử dụng thành phần này. Trong trường hợp của chúng tôi, nó là một loại thanh menu được sử dụng bởi nhiều chế độ xem. (Chế độ xem, trong trường hợp này, có nghĩa là các mục tiêu định tuyến.)

Việc tạo các thành phần như vậy dễ dàng hơn mong đợi. Dù sao thì tôi cũng đã dành gần cả ngày để tìm ra giải pháp đó, tôi đã chơi với các nhà cung cấp chế độ xem và mẫu, cố gắng truy cập vào mẫu và thao tác với mẫu. Tôi cũng đã cố gắng tạo một chỉ thị cấu trúc của riêng mình.

Nhưng bạn chỉ cần sử dụng chỉ thị trong thành phần vùng chứa.

<nav>  <div class="navigation pull-left">    <ul>      <!-- the menu items --->    </ul>  </div>  <div class="pull-right">    <ng-content></ng-content>  </div></nav

Đó là tất cả. Bạn không cần phải viết bất kỳ mã TypeScript nào để làm việc này. Sử dụng thành phần này bây giờ khá trực quan:

<div class="nav-bar">  <app-navigation>    <button (click)="printDraft($event)">print draft</button>    <button (click)="openPreview($event)">Show preview</button>  </app-navigation></div>

Nội dung của - các nút - bây giờ sẽ được đặt vào trình giữ chỗ.

Sau khi dành gần cả ngày để làm việc này, câu hỏi đầu tiên của tôi là: Nó có thực sự dễ dàng như vậy không? Vâng, đúng vậy. Đó là tất cả.

Có thể bạn đã biết về nó. Nhưng tôi không thể tìm thấy bất kỳ gợi ý nào trong tài liệu, trên StackOverflow hoặc trong bất kỳ Blog nào về nó. Có thể yêu cầu này không được sử dụng thường xuyên. Ít nhất tôi đã tình cờ tìm thấy một tài liệu mà ng-content được sử dụng và tôi quyết định viết về nó. Hy vọng nó sẽ giúp ích cho người khác.

3 hữu ích0 bình luận6.4k xemchia sẻ

Trước đây, nếu bạn biết một chút về mã hóa và thỉnh thoảng có thể làm tài liệu tham khảo về Chiến tranh giữa các vì sao, bạn được coi là một chuyên gia về Nhà phát triển web. Không còn nữa. Sự phát triển web đã chuyển sang xu hướng chủ đạo và số lượng các nhà phát triển ngoài kia đã tăng lên đáng kể.

Điều đó có nghĩa là nếu bạn muốn trở thành một chuyên gia trong lĩnh vực này, bạn cần phải giỏi hơn, hiểu biết hơn và có năng lực hơn các đối thủ cạnh tranh. Tuyệt vời, một số bạn có thể nghĩ, nhưng làm thế nào để bạn làm điều đó? Một câu hỏi hay - một câu hỏi mà chúng tôi sẽ dành phần còn lại của bài viết để khám phá.

Bạn cần phải đi sâu hơn

Giờ đây, bất kỳ ai có kết nối Internet đều có thể học cách viết mã (có toàn bộ kênh YouTube dành cho việc này ). Tuy nhiên, bạn cần biết nhiều hơn chúng. Điều này có nghĩa là không ngồi trên vòng nguyệt quế của bạn. Thay vào đó, bạn cần phải thường xuyên trau dồi các kỹ năng của mình, để bạn biết điều gì đang xảy ra, khi nào nó xảy ra và nó ảnh hưởng như thế nào đến những gì bạn đang làm.

Để có thể làm điều này một cách chính xác, bạn cần phải biết nơi để xem xét. Những trang web và tạp chí quan trọng? Chuyên gia nào biết họ đang nói gì và 'chuyên gia' nào không thể tìm ra lỗi trong một dòng mã?

Bạn thấy đấy, đó là nơi bạn có lợi thế hơn so với những người đàn ông ngực khủng. Họ chưa biết nghe ai. Bạn làm. Và điều đó có nghĩa là chi phí duy trì cập nhật sẽ nhỏ hơn nhiều.

Bạn cần phải rộng hơn

Điều đó nói rằng, việc viết mã một mình không giúp bạn đạt được điều đó - đặc biệt là vì có khá nhiều nền tảng ngoài kia, điều đó có nghĩa là bạn không phải thực sự nhập mã nữa. Họ sẽ làm rất nhiều điều đó cho bạn. Kết quả? Bộ kỹ năng của bạn cần được mở rộng . Bạn cần phải trở nên tốt hơn trong cách cư xử với mọi người, bởi vì nếu bạn không làm như vậy, họ sẽ chỉ tự làm điều đó mà thôi.

Và sau đó bạn sẽ đặt bánh mì trên bàn như thế nào?

Vì vậy, bạn không thể chỉ là một chuyên gia về web, bạn còn phải trở thành một chuyên gia về những gì người dùng muốn, cần và mong đợi. Điều đó có nghĩa là hiểu tâm lý người dùng (và khách hàng) để bạn có thể thúc đẩy họ một cách tinh tế theo hướng mong muốn.

Bạn cần hiểu thiết kế

Bạn viết mã giỏi đến đâu không quan trọng, nếu sản phẩm bạn cung cấp trông giống như phân bò, thì không ai sẽ làm việc với bạn. Và cách duy nhất để bạn có thể tạo ra một thứ gì đó thực sự trông đẹp mắt là ít nhất phải có hiểu biết cơ bản về thiết kế.

Các thanh phải rộng bao nhiêu? Sự kết hợp màu nào là hấp dẫn nhất? Cách bố trí nào là hiệu quả nhất? Mọi người mong đợi gì từ một trang web?

Bạn phải có khả năng trả lời tất cả những câu hỏi này, bởi vì, nếu bạn may mắn, khi bạn nói chuyện với một khách hàng mới, họ sẽ hỏi điều đó. Nếu bạn không may mắn, họ sẽ có những ý tưởng riêng của họ, điều này sẽ không hiệu quả, trong trường hợp này, bạn cần đủ hiểu biết để giải thích cho họ lý do tại sao không nên theo đuổi chúng. Nếu không, bạn có thể chắc chắn rằng họ sẽ đổ lỗi cho bạn vì trang web của họ không hoạt động. Và đó chỉ là những cơn đau đầu xung quanh!

Bạn cần được bảo mật

Một lĩnh vực khác mà bạn phải biết công cụ của mình là bảo mật, bởi vì nếu công cụ của bạn bị tấn công, thì bạn có thể khá chắc chắn rằng sẽ không ai coi bạn là một chuyên gia lâu hơn nữa.

Nhận ra rằng chỉ biết về bảo mật không có nghĩa là bạn cần phải lập trình tất cả các khía cạnh bảo mật. Trên thực tế, tôi khuyên bạn không nên làm điều đó, bởi vì nếu bạn mắc lỗi trong việc tạo hệ thống bảo mật của riêng mình, rất có thể bạn sẽ không phát hiện ra cho đến khi bạn bị tấn công. Và đến thời điểm đó, đã quá muộn và bạn cũng có thể bắt đầu tìm kiếm một con đường sự nghiệp mơ ước khác vì tin tặc vừa đập cửa vào mặt bạn vì con đường này.

Thay vào đó, hãy biết ngành đang làm gì và tại sao họ lại làm điều đó. Biết những gì đã được thử nghiệm cho đến chết và vẫn còn đứng. Và hãy đảm bảo rằng bất cứ thứ gì bạn đã phát triển đều được cập nhật!

Bạn cần hiểu cách tiếp xúc

Ngày nay, xây dựng một trang web là không đủ. Bạn phải chắc chắn rằng nó cũng được phơi bày. Điều này có thể có nhiều hình thức. Ví dụ: bạn có phát triển các trang web của mình để chúng được tối ưu hóa cho cả SEO cũng như phương tiện truyền thông xã hội không?

Bởi vì nếu bạn không làm vậy, thì không ai thực sự sẽ tìm thấy những viên ngọc mà bạn đang đặt ngoài đó. Và nếu không ai nhìn vào họ, thì sẽ không ai gọi bạn là một guru hay đeo bám từng lời nói của bạn.

Vì vậy, hãy đảm bảo rằng nội dung của bạn thực sự nhận được sự hiển thị xứng đáng, bằng cách đảm bảo rằng bạn hiểu các bản cập nhật mới nhất của Google, các thay đổi mới nhất trên mạng xã hội và cách tận dụng chúng theo cách tốt nhất có thể.

Hiểu những thay đổi sắp tới

Máy tính sẽ thay đổi trong những năm tới. Nó vẫn chưa rõ ràng theo hướng nào. Nó có thể là lượng tử, nó có thể là AI, nó có thể là máy học, nó có thể là dữ liệu lớn. Nhưng nó sẽ thay đổi. Và nếu bạn chưa sẵn sàng cho nó, bạn có thể thấy mình đang đi sai hướng của lịch sử.

Vì lý do đó, điều quan trọng là bạn phải cập nhật và nhận ra những gì sẽ thay đổi và nó sẽ thay đổi như thế nào để bạn có thể hiểu những gì bạn phải học để duy trì một bước so với thủy triều đang lên của cảnh biển máy tính đang thay đổi . Vì nếu không, bạn có thể thấy rằng lĩnh vực mà bạn là chuyên gia đột nhiên trở nên lỗi thời. Và ai muốn trở thành một guru trong một lĩnh vực mà không ai còn chú ý đến?

Bạn cần tiếp tục phát triển

Nếu bạn muốn trở thành một nhà phát triển web, bạn phải chấp nhận rằng bạn đang ở một trong những khu vực thay đổi nhanh chóng nhất hiện nay. Và nếu bạn không thay đổi với nó, bạn sẽ nhanh chóng đi theo con đường của loài khủng long.

Vì vậy, hãy tiếp tục học hỏi, tiếp tục phát triển, tiếp tục nhận ra rằng những gì có thể đã hoạt động vài tháng trước có thể không còn đủ tốt cho ngày hôm nay. Không giống như trong các lĩnh vực cũ, nơi mà kiến ​​thức là tĩnh, đó là những gì thực sự cần để trở thành một chuyên gia trong lĩnh vực phát triển web.

Rốt cuộc, bạn có thường xuyên nghe mọi người tham khảo các văn bản từ thế kỷ trước khi họ nói về phát triển web không? Vì vậy, đừng là thế kỷ trước, thậm chí đừng là năm ngoái. Hãy cập nhật và bạn có thể yêu cầu lớp áo của Guruship.

1 hữu ích0 bình luận15k xemchia sẻ

Tôi nghĩ về các bài kiểm tra đơn vị như một phần mở rộng cho mã của tôi. Quá trình kiểm tra kỹ lưỡng mang lại sự an tâm rằng khi cấu trúc lại mã hoặc thực hiện cải tiến hiệu suất, các thiết bị vẫn hoạt động như mong đợi. Nó cũng có thể tìm ra lỗi và các trường hợp cạnh và tránh hồi quy trong quá trình tái cấu trúc.

Tôi đến từ nền tảng .NET / C # và đã biên soạn bộ sưu tập những suy nghĩ và mẩu tin nhỏ này mà tôi thấy hữu ích khi viết bài kiểm tra.

Tại sao phải viết bài kiểm tra đơn vị?

Tôi thấy rằng việc viết các bài kiểm tra đơn vị và viết mã có thể bảo trì mạnh mẽ thường đi đôi với nhau. Nếu logic bạn đang kiểm tra được trộn lẫn với các thành phần UI, bạn có thể thấy rằng các thành phần cần được tải (có thể trong một chuỗi UI) để các bài kiểm tra có quyền truy cập vào logic. Nếu nhiều lớp được kết hợp chặt chẽ với nhau, thì thiết lập cho một bài kiểm tra đơn vị có thể bị phức tạp. Những ví dụ này và nhiều ví dụ khác về việc kiểm tra đơn vị trở nên khó khăn là một dấu hiệu cho thấy mã có thể được hưởng lợi từ một số cấu trúc lại tốt.

Phương pháp tiếp cận kiểm thử đơn vị

Kiểm tra hộp đen là nơi bạn kiểm tra một đơn vị mà không có quyền truy cập vào mã nguồn của đơn vị hoặc bằng cách từ chối xem xét nó. Để thực hiện kiểm tra hộp đen, bạn có thể biết, được thông báo hoặc thử nghiệm với những gì được mong đợi ở thiết bị.

Kiểm thử hộp trắng là nơi bạn kiểm tra mã nguồn của đơn vị được kiểm tra để hỗ trợ viết các bài kiểm tra đơn vị. Bằng cách kiểm tra mã nguồn, bạn sẽ có thể đảm bảo rằng các bài kiểm tra của bạn bao gồm chung tất cả các đường dẫn mã trong mỗi hành động. Điều này bao gồm việc cung cấp cho các giới hạn của bất kỳ vòng lặp nào và tuân theo tất cả các điều kiện logic. Chắc chắn cũng có thể đạt được mức độ phủ mã này với kiểm tra hộp đen, chẳng hạn như nếu thiết bị đủ đơn giản để thử tất cả các đầu vào hoặc kết hợp trạng thái có thể. Kiểm tra hộp trắng có thể giúp nắm bắt các tình huống khó hiểu mà bạn có thể không nghĩ đến nếu không nhìn thấy mã.

Trạng thái thử nghiệm bao gồm việc thực hiện một hành động trên một thiết bị và sau đó kiểm tra xem kết quả mong đợi đã được trả về hay trạng thái của thiết bị đã được cập nhật như mong đợi. Trạng thái thử nghiệm có thể đạt được bất kể bạn đang thử nghiệm hộp trắng hay hộp đen.

Triển khai thử nghiệm là một phần mở rộng cho thử nghiệm hộp trắng trong đó bạn kiểm tra xem các phương pháp nhất định có được gọi hay không trong khi thực hiện một hành động. Ở đây, bạn không khẳng định bất kỳ trạng thái nào, nhưng thay vào đó hãy xác minh rằng hành vi nội bộ đang làm những gì được mong đợi.

Giải phẫu của một bài kiểm tra đơn vị

Một thử nghiệm đơn vị duy nhất xác nhận trạng thái thường được tạo thành từ ba giai đoạn sau:

  1. 'Sắp xếp' chuẩn bị mọi thứ sẵn sàng để thực hiện kiểm tra. Điều này có thể là khai báo các biến, xây dựng các đối tượng được yêu cầu hoặc thiết lập trạng thái của một đơn vị dựa trên các trường hợp chúng ta muốn kiểm tra. Một số hoặc tất cả bước này có thể diễn ra trong phương pháp SetUp của bộ cố định kiểm tra đơn vị hiện tại. Đối với các thử nghiệm đơn vị đơn giản, bước này có thể không cần thiết.

  2. 'Hành động' thực hiện hành động mà chúng tôi đang thử nghiệm trên thiết bị.

  3. Kiểm tra 'Khẳng định' để xem rằng hành động được thực hiện chính xác. Chúng ta muốn kiểm tra xem giá trị trả về của một cuộc gọi phương thức có được mong đợi hay trạng thái của một đối tượng là như mong đợi.

Một ví dụ là:

[Test]public void GetMinimum_UnsortedIntegerArray_ReturnsSmallestValue(){  var unsortedArray = new int[] {7,4,9,2,5}; // Arrange   var minimum = Statistics.GetMinimum(unsortedArray); // Act   Assert.AreEqual(2, minimum); // Assert}

Hướng dẫn cấu trúc một bài kiểm tra đơn vị

Dưới đây là một số nguyên tắc bạn có thể làm theo khi viết bài kiểm tra đơn vị:

  • Giữ số lượng xác nhận cho mỗi đơn vị thử nghiệm ở mức tối thiểu. Một bài kiểm tra đơn vị là kiểm tra một thứ. Nhiều xác nhận trong một thử nghiệm duy nhất là tốt, nhưng nếu chia các xác nhận thành các thử nghiệm riêng biệt là hợp lý, thì tốt nhất bạn nên làm như vậy.

  • Tránh các thử nghiệm ít xác nhận. Đây là những bài kiểm tra không chứa bất kỳ xác nhận nào (hoặc xác minh trong trường hợp kiểm tra triển khai) và được sử dụng để kiểm tra xem một thứ gì đó hoạt động mà không đưa ra ngoại lệ. Tôi thích các bài kiểm tra đơn vị của mình để luôn kiểm tra xem có điều gì đó hoạt động hay không.

  • Không lặp lại các xác nhận đã được đề cập trong các thử nghiệm hiện có. Nếu một kiểm thử đơn vị khẳng định rằng một kết quả không phải là rỗng hoặc một tập hợp có chính xác một mục, thì kiểm thử đơn vị tiếp theo không cần lặp lại các khẳng định như vậy trước khi khẳng định trạng thái bổ sung.

  • Các xác nhận nên được đặt trong các bài kiểm tra đơn vị phù hợp, thay vì được đưa ra trong các phương pháp trợ giúp. Nếu việc kiểm tra trạng thái hơi phức tạp và phổ biến trong nhiều bài kiểm tra, thì tốt hơn là bạn nên viết một phương thức trợ giúp để kiểm tra trạng thái. Sau đó, thật dễ dàng để đặt các xác nhận bên trong phương thức trợ giúp đó, mặc dù tôi thấy các bài kiểm tra đơn vị dễ đọc hơn nếu chúng chứa các xác nhận có thể kiểm tra boolean được phương thức trợ giúp trả về.

  • Mã để sắp xếp, hành động và khẳng định phải nằm trên các dòng riêng của chúng, lý tưởng nhất là có một dòng mới giữa mỗi dòng. Nếu bạn đang xác nhận rằng một phương thức trả về true, bạn có thể thực hiện lệnh gọi phương thức đó ngay bên trong câu lệnh khẳng định. Tôi thấy các bài kiểm tra đơn vị rõ ràng hơn khi chúng được giữ riêng biệt.

Kiểm tra đôi

Kiểm thử đơn vị chỉ liên quan đến việc kiểm tra một đơn vị duy nhất, chứ không phải là liệu nhiều đơn vị có hoạt động chính xác với nhau hay không. Một số người xem một đơn vị là một lớp, những người khác như một phương thức. Dù bằng cách nào, một đơn vị đơn lẻ thường yêu cầu các đối tượng khác để hoạt động chính xác. Để biên dịch các bài kiểm tra, chúng tôi có thể xây dựng các đối tượng thực và cung cấp chúng cho đơn vị đang kiểm tra theo cách giống như cách chúng tôi làm khi sử dụng đơn vị trong sản xuất. Tuy nhiên, bằng cách làm điều này, chúng tôi bắt đầu rời khỏi việc thực sự chỉ thử nghiệm một đơn vị duy nhất và ghép mã thử nghiệm với nhiều đơn vị hơn những gì nó liên quan. Thậm chí có thể không thực tế khi sử dụng các đối tượng thực nếu chúng kết nối với các công nghệ bên ngoài như dịch vụ web của bên thứ ba, hệ thống xếp hàng hoặc kho dữ liệu.

Đây là nơi các bộ đôi thử nghiệm xuất hiện. Có nhiều bộ đôi thử nghiệm khác nhau mà chúng ta có thể sử dụng để thay thế cho các đối tượng thực tế. Mục đích của việc này chỉ là để đáp ứng các yêu cầu của việc sử dụng thiết bị đang được thử nghiệm. Sau đây là những bộ đôi thử nghiệm mà tôi biết và đã sử dụng.

Hình nộm

Hình nộm thường là các giá trị không quan trọng nhưng cần thiết để gọi một phương thức mà chúng tôi đang thử nghiệm. Giá trị có thể không liên quan vì nó không ảnh hưởng đến thử nghiệm nhưng cần tồn tại để gọi phương thức. Các tham số của chúng tôi là một ví dụ phổ biến về điều này:

[Test]public void GetOccurrences_NewDateTimePattern_HasZeroOccurrences(){  var pattern = new DateTimePattern();  var dummy;   var count = pattern.GetOccurrences(out dummy);   Assert.AreEqual(0, count);}

Stubs

Stub là các phương thức được mã hóa cứng trả về một câu trả lời mong đợi và không quan tâm đến các đối số của phương thức hoặc trạng thái của bất kỳ đối tượng nào, vì vậy không hoạt động bình thường. Chúng có thể là các hàm ẩn danh được chuyển trực tiếp đến một phương thức trên đơn vị mà chúng tôi đang thử nghiệm, trong trường hợp đó, chúng tôi đang kiểm tra xem đơn vị đó có hoạt động chính xác hay không khi hàm trả về kết quả được mã hóa cứng đó. Sơ khai có thể là một phương thức được triển khai như một yêu cầu của một giao diện mà đơn vị được kiểm tra cần gọi. Ví dụ, một sơ khai kiểm tra sự tồn tại của một tệp có thể luôn trả về true nếu chúng tôi không thực sự sử dụng hệ thống tệp trong khi kiểm tra đơn vị:

public bool FileExists(string path){  return true;}

Đồ giả

Giả mạo là các đối tượng hoàn toàn có chức năng thường triển khai một giao diện hoặc ít nhất là mở rộng một lớp trừu tượng mà đơn vị được kiểm tra cần. Giả mạo là những triển khai nhanh chóng và bẩn thỉu sẽ không được sử dụng ngoài vai trò là một bài kiểm tra đơn vị kép. Có rất nhiều ví dụ điển hình về hàng giả, gần đây tôi đã sử dụng hàng giả để triển khai giao diện IRedisClient (kho lưu trữ cấu trúc dữ liệu). Thay vì thực sự chạy Redis, dữ liệu được lưu trữ trong cấu trúc dữ liệu C # theo cách rất đơn giản. Các đơn vị đang được kiểm tra yêu cầu IRedisClient để hoạt động có thể được cung cấp một trường hợp giả mạo đó thay vì dựa vào Redis để chạy:

public class FakeRedisClient : IRedisClient{  private Dictionary<string, object> _redis = new Dictionary<string,object>();   // and so on   public void AddItemToSet(string setId, string item)  {    object obj;    _redis.TryGetValue(setId, out obj);    HashSet set = (HashSet)obj;    if (set == null)    {      set = new HashSet();      _redis[setId] = set;    }    set.Add(item);  }   // and so forth}

Mocks

Mocks được sử dụng để kiểm tra hành vi hoặc việc thực hiện nội bộ, thay vì trạng thái. Bạn sử dụng chúng để xác minh, ví dụ, một số chức năng nhất định đã được gọi hoặc không được gọi do gọi phương thức bạn đang thử nghiệm. Chế độ giả thường đạt được với sự trợ giúp của các khuôn khổ chế tạo như Moq cho .NET. Bạn mô phỏng một đối tượng từ một giao diện cung cấp cho bạn một đối tượng cụ thể để làm việc. Là một phần của thiết lập, bạn có thể đính kèm các bit logic hoặc các giá trị được mã hóa cứng thay cho các phương thức hoặc thuộc tính. Điều này được thực hiện để đối tượng được chế tạo hoạt động chính xác khi đơn vị được kiểm tra sử dụng. Một đối tượng giả mạo có thể giống về mặt chức năng với đồ giả và có khả năng được sử dụng để kiểm tra trạng thái. Tôi nghiêm túc sử dụng mocks chỉ trong một vài trường hợp tôi viết các bài kiểm tra triển khai.

[SetUp]public void SetUp(){  _customer = new Mock();  _customer.Setup(c => c.PaymentID).Returns(1);} [Test]public void CreateSubscription_NewCustomer_ExistingSubscriptionsAreChecked(){  var service = CreatePaymentSubscriptionService();   var subscription = service.CreateSubscription(_customer);   _customer.Verify(c => c.GetSubscriptions());}

Vì vậy, cá nhân tôi đứng ở đâu?

Tôi chủ yếu viết các bài kiểm tra cho mã mà tôi viết và điền vào các bài kiểm tra còn thiếu cho mã mà tôi có quyền truy cập. Do đó, tôi chắc chắn là một người thử nghiệm hộp trắng. Đối với việc triển khai trạng thái và trạng thái, tôi chủ yếu tập trung vào trạng thái thử nghiệm. Tôi muốn đảm bảo rằng một đơn vị đang hoạt động chính xác như được quan sát bên ngoài mà không có giả định nào về cách nó hoàn thành công việc. Đây là cách các đơn vị khác trong một chương trình đang chạy sẽ nhìn thấy và tương tác với nó. Điều này nghe có vẻ giống như kết quả của kiểm tra hộp đen sẽ đạt được. Kiểm tra hộp trắng mang lại cho tôi lợi ích bổ sung là đảm bảo tất cả các đường dẫn mã và bất kỳ trường hợp cạnh nào bị che khuất đều được xác nhận.

Bạn có thể thấy rằng việc thử nghiệm chủ yếu theo tiểu bang khiến việc triển khai tự do thay đổi nhiều hơn. Bất kỳ phần nào của quá trình triển khai không được kết hợp với API chẳng hạn như cấu trúc dữ liệu được sử dụng, cách dữ liệu được định dạng, các khóa được sử dụng để lưu trữ dữ liệu, v.v. thì sẽ không đề cập đến những điều này trong các bài kiểm tra trạng thái của tôi. Bằng cách cập nhật quá trình triển khai nội bộ mà không ảnh hưởng đến API hoặc kết quả mong đợi, bạn sẽ có thể chạy các bài kiểm tra đơn vị để tìm thấy đơn vị vẫn hoạt động như bình thường.

Nếu chủ yếu kiểm tra bằng cách triển khai, các bài kiểm tra đơn vị trở nên kết hợp chặt chẽ với việc triển khai nội bộ đó có thể làm cho các bài kiểm tra khá giòn. Việc thay đổi cách triển khai sẽ phá vỡ các bài kiểm tra và yêu cầu viết lại chúng.

Điều đó nói rằng, một vài thử nghiệm triển khai ở đây và ở đó có thể hữu ích. Ví dụ: có một đơn vị chứa cấu trúc dữ liệu được sử dụng làm bộ đệm ẩn bên trong để giải quyết các vấn đề về hiệu suất. Đây hoàn toàn là một quyết định thực hiện mà bên ngoài đơn vị không cần biết. API của đơn vị không tiết lộ bất kỳ điều gì liên quan đến trạng thái của bộ nhớ cache nội bộ này, vì vậy không có cách nào để khẳng định điều đó. Để yên tâm, bạn có thể kiểm tra xem bộ nhớ đệm này có được quản lý tốt hay không, chẳng hạn như xóa các mục khi thích hợp. Để làm điều này, có thể tốt hơn là sử dụng thử nghiệm triển khai, nếu bạn không muốn phơi bày sự tồn tại của bộ nhớ đệm theo một cách nào đó để kiểm tra trạng thái của nó.

Tôi không nghiêm khắc buộc bản thân chỉ kiểm tra theo trạng thái và bỏ qua kiểm tra triển khai. Tôi nghĩ rằng thật tốt khi biết những cách tiếp cận nào có sẵn và chọn công cụ phù hợp cho công việc.

Bạn có bất kỳ ví dụ kiểm tra đơn vị hoặc nguyên tắc cá nhân nào mà bạn muốn chia sẻ không? Cho chúng tôi biết trong các ý kiến ​​dưới đây.

Last updated