123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- <html>
- <head>
- <title>Jasmine - Unit Testing</title>
- <link href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css" rel="stylesheet" type="text/css" />
- <link href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css" rel="stylesheet" type="text/css" />
- <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript"></script>
- <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js" type="text/javascript"></script>
- <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js" type="text/javascript"></script>
- <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushBash.js" type="text/javascript"></script>
- <style type="text/css">
- .new-page {page-break-before: always;}
- </style>
- </head>
- <body>
- <h2>I. Introduction:</h2>
- <p>In this tutorial we will take an existing Ext application and introduce the Jasmine assertion library for unit
- testing. Readers must be familiar with JavaScript, ExtJS 4, the MVC architecture as well as the fundamentals of
- HTML, CSS, and using resources.</p>
- <p><b>Why Test?</b>
- There are many reasons to test applications. Tests can verify an application's functionality to eliminate the
- need to enumerate all the use cases manually. Also, if the application were to be refactored, or updated,
- the tests could verify that the changes did not introduce new bugs into the system</p>
- <h2>II. Getting started.</h2>
- <p>For this tutorial, use the "simple" example of the MVC in the ExtJS bundle — found under
- <ext>/examples/app/simple. Copy the simple folder to your workspace or desktop.</p>
- <p>Add these folders:</p>
- <pre class="brush: bash shell; toolbar: false; gutter: false">
- <simple dir>/app-test
- <simple dir>/app-test/specs</pre>
- <p>Download and extract the Jasmine standalone library into the app-test folder.
- <a href="http://pivotal.github.com/jasmine/download.html">Link</a></p>
- <p>Create these files (leave them empty for now, you will fill them in next)</p>
- <pre class="brush: bash shell; toolbar: false; gutter: false">
- <simple dir>/app-test.js
- <simple dir>/run-tests.html</pre>
- <p>Your project should look like this now:</p>
- <img src="folder.jpg"/>
- <p class="new-page">Now that you have the files and folders setup, fill in the test-running environment. Open the run-tests.html
- and put the following markup into it:</p>
- <pre class="brush: xml; toolbar: false; gutter: false;">
- <html>
- <head>
- <title id="page-title">Tester</title>
- <link rel="stylesheet" type="text/css" href="app-test/lib/jasmine-1.1.0/jasmine.css">
-
- <script type="text/javascript" src="extjs/ext-debug.js"></script>
- <script type="text/javascript" src="app-test/lib/jasmine-1.1.0/jasmine.js"></script>
- <script type="text/javascript" src="app-test/lib/jasmine-1.1.0/jasmine-html.js"></script>
- <!-- include specs here -->
- <!-- test launcher -->
- <script type="text/javascript" src="app-test.js"></script>
- </head>
- <body>
- </body>
- </html></pre>
- <p>There are a few key things to remember here: the jasmine resources, the ext framework resource and app-test.js.
- These will need to be included with your tests (this order is important). You will include the specs
- (jasmine assertion js files) above the app-test.js and below the rest of the files.</p>
- <p>Next, open app-test.js and copy this code into it:</p>
- <pre class="brush: js; toolbar: false; gutter: false;">
- Ext.require('Ext.app.Application');
- var APPLICATION = null;
- Ext.onReady(function() {
- APPLICATION = Ext.create('Ext.app.Application', {
- name: 'AM',
- controllers: [
- 'Users'
- ],
- launch: function() {
- //include the tests in the test.html head
- jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
- jasmine.getEnv().execute();
- }
- });
- });</pre>
- <p>The effect of the above code is a global reference to the <i>Application</i> instance and bootstrap for the
- jasmine assertion library. This is accomplished by directly constructing the <i>Application</i> object and
- storing the reference when the document is ready, bypassing the Ext.application() method.</p>
- <p><b>Note:</b> this <i>Application</i> definition is not a copy and paste of your regular <i>Application</i>
- definition in your app.js. This version will only include the controllers, stores, models, etc and when
- <i>launch</i> is called it will invoke the Jasmine tests.</p>
- <p>Now should you have a working test environment.</p>
- <h2>III. Writing Tests.</h2>
- <p>Under the specs folder (<simple>/app-test/specs) create two empty text files named:</p>
- <pre class="brush: bash shell; toolbar: false; gutter: false;">
- example.spec.js
- users.spec.js</pre>
- <p>Then go back to the <i>run-tests.html</i> file and add these two lines under the comment <i>"<!-- include
- specs here -->"</i></p>
- <pre class="brush: xml; first-line: 12; toolbar: false; gutter: false"><!-- include specs here -->
- <script type="text/javascript" src="app-test/specs/example.spec.js"></script>
- <script type="text/javascript" src="app-test/specs/users.spec.js"></script></pre>
- <p><b>Note:</b> You may have noticed a pattern in the file names. Although, not required, its nice to indicate what
- the file is for. (in this case the double extension of *.spec.js)</p>
- <p>Start by filling in example.spec.js. Jasmine's specification syntax is very descriptive. Each suite of tests is
- contained in a describe function, and each test is defined by an "it" function.</p>
- <p>Example:</p>
- <pre class="brush: js; toolbar: false; gutter: false">
- describe("Basic Assumptions", function() {
- it("has ExtJS4 loaded", function() {
- expect(Ext).toBeDefined();
- expect(Ext.getVersion()).toBeTruthy();
- expect(Ext.getVersion().major).toEqual(4);
- });
- it("has loaded AM code",function(){
- expect(AM).toBeDefined();
- });
- });</pre>
- <p>To pass a test (each "it" block) simply call <i>expect(someValue).toBe<something>()</i></p>
- <p class="new-page">Next a more complicated example. Testing a store, which is asynchronous, and retrieved from a Controller. (This
- is where that global application reference will come in handy)</p>
- <pre class="brush: js; toolbar: false; gutter: false">
- describe("Users", function() {
- var store = null, ctlr = null;
- beforeEach(function(){
- if(!ctlr) ctlr = APPLICATION.getController('Users');
- if(!store) store = ctlr.getStore('Users');
- expect(store).toBeTruthy();
- waitsFor(
- function(){ return !store.isLoading(); },
- "load never completed",
- 4000
- );
- });
- it("should have users",function(){
- expect(store.getCount()).toBeGreaterThan(1);
- });
- it("should add and be able to get", function(){
- store.add(Ext.create('AM.model.User', {
- name: "John Doe",
- email: "john.doe@anon.net"
- }));
- var user = store.findRecord('name', 'John Doe');
- expect(user).toBeTruthy();
- expect(user.get('email')).toBe('john.doe@anon.net');
- });
- it("should open the editor window", function(){
- var grid = Ext.ComponentQuery.query('userlist')[0];
- ctlr.editUser(grid,store.getAt(0));
- var edit = Ext.ComponentQuery.query('useredit')[0];
- expect(edit).toBeTruthy();
- if(edit)edit.destroy();
- });
- });</pre>
- <p class="new-page">Notice the "beforeEach" function (this will be called before each "it"). This function sets
- up the stage for each test, and this example:
- <ol>
- <li>gets a <i>Store</i> from a <i>Controller</i></li>
- <li>asserts that the store was successfully retrieved (not null or undefined)</li>
- <li>waits for the store to complete loading — see the "waitFor" function — This store
- auto loads data when its constructed: do not run tests before its ready.</li>
- </ol>
- </p>
- <h2>IV. Automatting.</h2>
- <p>Combining this with PhantomJS allows us to run these tests from the command line or from a cron job. The provided
- <i>run-jasmine.js</i> in the PhantomJS distribution is all that is needed. (you can tweak it to make the output suit
- your needs, <a href="run-jasmine.js">here</a> is an example tweaked version )</p>
- <p>Example command line:</p>
- <pre class="brush: bash shell; toolbar: false; gutter: false">phantomjs run-jasmine.js http://localhost/app/run-tests.html</pre>
- <p>You will need to run the tests from a web server because XHR's cannot be made from the file:// protocol</p>
- <p><b>About the Author:</b>
- <a href="http://jonathangrimes.com">Jonathan Grimes</a> (<a href="http://www.facebook.com/jonathan.grimes">FB</a>,<a href="http://twitter.com/jsg2021">Tw</a>,<a href="https://plus.google.com/u/0/102578638400305127370/about">G+</a>) is a software engineer at <a href="http://nextthought.com">NextThought</a>, a technology start-up company that is currently building an integrated platform for online education. </p>
-
- <script type="text/javascript"> SyntaxHighlighter.all() </script>
- </body>
- </html>
|