CSC/ECE 517 Fall 2012/ch2a 2w30 an: Difference between revisions
No edit summary |
|||
(30 intermediate revisions by 2 users not shown) | |||
Line 2: | Line 2: | ||
=Introduction= | =Introduction= | ||
Testing plays a major role in the software development cycle. It is a well known fact that mandatory testing of every functionality implemented be done so as to ensure that the code does not break when in production. Testing can be done in four main stages: Unit testing (individual code modules are tested for flaws and re-coded if any errors are found), Integration testing (various interacting modules are put together piece by piece to ensure that seamless integration exists among them), System testing (the system is tested as a whole after it has been fully integrated) and Acceptance testing (potential users test the system for flaws in design or execution and to see if the product matches their expectation). | |||
This article focuses on Unit testing by following the Test Driven Development approach for Ruby using RSpec framework as explained in this [https://www.youtube.com/watch?v=oFX1KPNRruA&feature=relmfu SaaS] video. | |||
=Characteristics of a good Unit test= | =Characteristics of a good Unit test= | ||
*Fast: | *'''Fast''': | ||
**The tests should not take too long to run. Sometimes it would seem more logical to run only a subset of the tests (for example, when a part of the code breaks or only a particular functionality of the code is being developed). In such cases, it would not be productive if the tests take quite a bit of time to finish executing. | **The tests should not take too long to run. Sometimes it would seem more logical to run only a subset of the tests (for example, when a part of the code breaks or only a particular functionality of the code is being developed). In such cases, it would not be productive if the tests take quite a bit of time to finish executing. | ||
*Independent: | *'''Independent''': | ||
**When tests are being run, the order of execution of the tests should not matter. More importantly, tests should not be inter-dependent; which means that, it should be possible to run any subset of the test set in any order. Also, no test should be a prerequisite for another test. | **When tests are being run, the order of execution of the tests should not matter. More importantly, tests should not be inter-dependent; which means that, it should be possible to run any subset of the test set in any order. Also, no test should be a prerequisite for another test. | ||
*Repeatable: | *'''Repeatable''': | ||
**The output for a test execution should be consistent irrespective of the number of times that it is run. This is essential in order to isolate bugs and enable automation. If the test notices the presence of a bug on the first run, it should do so on every consecutive run. | **The output for a test execution should be consistent irrespective of the number of times that it is run. This is essential in order to isolate bugs and enable automation. If the test notices the presence of a bug on the first run, it should do so on every consecutive run. | ||
*Self-checking: | *'''Self-checking''': | ||
**Testing field has changed considerably. Where [http://en.wikipedia.org/wiki/Software_quality_assurance Quality Assurance] department was involved to check the functionality of the code, it is now all automated. It is therefore, now mandatory that all tests themselves know if it is a pass or fail. No human intervention should be expected. Also, tests can run in the back all the time which means that if there is a change in the code or when the code breaks, the test script should be able to identify the same without human intervention. | **Testing field has changed considerably. Where [http://en.wikipedia.org/wiki/Software_quality_assurance Quality Assurance] department was involved to check the functionality of the code, it is now all automated. It is therefore, now mandatory that all tests themselves know if it is a pass or fail. No human intervention should be expected. Also, tests can run in the back all the time which means that if there is a change in the code or when the code breaks, the test script should be able to identify the same without human intervention. | ||
*Timely: | *'''Timely''': | ||
**Testing should follow the [http://en.wikipedia.org/wiki/Test-driven_development Test Driven Development (TDD)] approach. Here, the test cases are written before the code is implemented or at least around the same time (and not after!). Hence, if the functionality of the code being tested changes, the respective test cases should change correspondingly. | **Testing should follow the [http://en.wikipedia.org/wiki/Test-driven_development Test Driven Development (TDD)] approach. Here, the test cases are written before the code is implemented or at least around the same time (and not after!). Hence, if the functionality of the code being tested changes, the respective test cases should change correspondingly. | ||
= | =DSL= | ||
[ | [http://en.wikipedia.org/wiki/Domain-specific_language Domain Specific Languages] (DSLs) are small programming languages that do only a small number of activities within a specific task domain. Thus we can say that a DSL is not general. | ||
Examples for DSLs include migration scripts (which are a small set of statements with the sole job of expressing changes in the database schema), [http://en.wikipedia.org/wiki/Regular_expression Regexes], [http://en.wikipedia.org/wiki/SQL SQL]. | |||
= | =RSpec= | ||
[http://en.wikipedia.org/wiki/RSpec RSpec] is a testing tool for [http://en.wikipedia.org/wiki/Ruby_%28programming_language%29 Ruby] <sup>[http://rspec.info/]</sup>. It is based on [http://en.wikipedia.org/wiki/Behavior-driven_development Behavior Driven Development(BDD)] framework and is inspired by [http://jbehave.org/ JBehave] which is another BDD testing framework <sup>[http://en.wikipedia.org/wiki/RSpec]</sup>. RSpec is considered a DSL for writing tests. The notable difference between RSpec and SQL is that, while RSpec is an internal DSL, SQL is stand alone. Internal or embedded DSLs are implemented within another language that acts as their host <sup>[http://en.wikipedia.org/wiki/Domain-specific_language]</sup>. | |||
==Features of RSpec== | |||
*Each test in RSpec is called a ''spec'' (which is short for specification). | |||
*RSpec code inhabits the Spec directory which mimics the directory structure of the application.''rspec:install'' is a [http://guides.rubyonrails.org/command_line.html Rails generator] that creates the sub-directory structure for the Spec directory. | |||
*Specs are usually written for the controller and model methods. View spec checking is done mostly using the controller spec (seeing that the view will call controller method) and so, specs are usually not written for view. Instead, one can use [http://en.wikipedia.org/wiki/Cucumber_%28software%29 Cucumber] to test the view functionality. | |||
{| class="wikitable" | |||
! Apps folder !! Spec folder | |||
|- | |||
| app/models/*.rb || spec/models/*_spec.rb | |||
|- | |||
|app/controllers/ *_controller.rb || spec/controllers/ *_controller_spec.rb | |||
|- | |||
| app/views/*/*.html.erb || Use Cucumber | |||
|} | |||
User stories are taken as the input to write RSpecs. The following is an example of one such user story: | |||
<pre> | |||
When I fill in "Search Posts" with "Assignments" | |||
And I press "Search" | |||
Then I should be on the Posts page with Assignment Posts | |||
</pre> | |||
Once we have the user stories ready, the next is to implement the corresponding code to realize this test case. | |||
==The code we wish we had== | |||
When the user clicks on the button in the view for search_posts, the controller action receives the form submission and should perform the following actions: | |||
#It will call a method that searches the BackChannel App for posts with the specified search term(s) | |||
#It then calls the model method to check the database to see if the entered value exists. | |||
#If there is a match, a view with the Posts corresponding to the search terms is rendered. If no match is found, there should be a redirection to the homepage with an error message for the user's information. | |||
The RSpec for the above mentioned scenario can be written as follows: | |||
<pre> | |||
require 'spec_helper' | |||
describe PostController do | |||
describe 'searching Posts' do | |||
it 'should call the model method that performs Post search' | |||
it 'should select the Search Results template for rendering' | |||
it 'should make the Post search results available to that template' | |||
end | |||
end | |||
</pre> | |||
Spec_helper is a file that RSpec creates as a part of the install step <sup>[http://jeffkreeftmeijer.com/2011/spec-helpers-bundler-setup-faster-rails-test-suites/]</sup>. This file ensures that the functions required for testing are loaded. The behavior of the post controller is described in the code block. The main behavior that we are focusing on is searching post. | |||
In the code, ''it'' is a method that takes in a string parameter. This string describes the actions to be performed that corresponds to the specification given in the user story. Further behaviors can be added to or nested within the main describe block, or new test scripts can be written, as per requirements. | |||
=Summary= | |||
A good test case must adhere to the FIRST principle (Fast, Independent, Repeatable, Self-checking, Timely). TDD or Test Driven Development is the approach in which test cases are written for code even before the implementation is realized. DSLs or Domain Specific Languages take on a very specialized set of tasks. When unit tests are written using RSpec, which is an embedded DSL for Ruby testing, we usually write the tests for the controller and model methods and leave the view testing to Cucumber. The Spec files are stored in the Spec directory which mimics the application directory structure. RSpec can be used to perform unit and functional testing. | |||
=References= | =References= | ||
#http://rspec.info/ | |||
#http://en.wikipedia.org/wiki/RSpec | |||
#http://en.wikipedia.org/wiki/Domain-specific_language | |||
#http://jeffkreeftmeijer.com/2011/spec-helpers-bundler-setup-faster-rails-test-suites/ | |||
=Also see= | =Also see= | ||
*https://www.youtube.com/watch?v=oFX1KPNRruA&feature=relmfu | |||
*http://en.wikipedia.org/wiki/Software_quality_assurance | |||
*http://en.wikipedia.org/wiki/Test-driven_development | |||
*http://en.wikipedia.org/wiki/Regular_expression | |||
*http://en.wikipedia.org/wiki/SQL | |||
*http://en.wikipedia.org/wiki/Ruby_%28programming_language%29 | |||
*http://en.wikipedia.org/wiki/Behavior-driven_development | |||
*http://jbehave.org/ | |||
*http://en.wikipedia.org/wiki/Domain-specific_language | |||
*http://guides.rubyonrails.org/command_line.html | |||
*http://en.wikipedia.org/wiki/Cucumber_%28software%29 | |||
*http://pastebin.com/kJxjwSF6 | |||
=Other Interesting Links= | |||
*[http://net.tutsplus.com/tutorials/php/the-newbies-guide-to-test-driven-development/ Newbies guide to TDD] | |||
*[http://www.codeproject.com/Articles/9099/The-30-Minute-Regex-Tutorial The 30 minute Regex tutorial] | |||
*[http://www.andrejkoelewijn.com/wp/2008/10/27/sql-is-a-dsl/ SQL is a DSL] | |||
*[https://www.relishapp.com/rspec RSpec] | |||
*[https://www.relishapp.com/rspec/rspec-rails/v/2-0/docs/helper-specs/helper-spec Spec helper] |
Latest revision as of 01:45, 27 October 2012
SaaS - 5.2 - FIRST, TDD and getting started with RSpec
Introduction
Testing plays a major role in the software development cycle. It is a well known fact that mandatory testing of every functionality implemented be done so as to ensure that the code does not break when in production. Testing can be done in four main stages: Unit testing (individual code modules are tested for flaws and re-coded if any errors are found), Integration testing (various interacting modules are put together piece by piece to ensure that seamless integration exists among them), System testing (the system is tested as a whole after it has been fully integrated) and Acceptance testing (potential users test the system for flaws in design or execution and to see if the product matches their expectation).
This article focuses on Unit testing by following the Test Driven Development approach for Ruby using RSpec framework as explained in this SaaS video.
Characteristics of a good Unit test
- Fast:
- The tests should not take too long to run. Sometimes it would seem more logical to run only a subset of the tests (for example, when a part of the code breaks or only a particular functionality of the code is being developed). In such cases, it would not be productive if the tests take quite a bit of time to finish executing.
- Independent:
- When tests are being run, the order of execution of the tests should not matter. More importantly, tests should not be inter-dependent; which means that, it should be possible to run any subset of the test set in any order. Also, no test should be a prerequisite for another test.
- Repeatable:
- The output for a test execution should be consistent irrespective of the number of times that it is run. This is essential in order to isolate bugs and enable automation. If the test notices the presence of a bug on the first run, it should do so on every consecutive run.
- Self-checking:
- Testing field has changed considerably. Where Quality Assurance department was involved to check the functionality of the code, it is now all automated. It is therefore, now mandatory that all tests themselves know if it is a pass or fail. No human intervention should be expected. Also, tests can run in the back all the time which means that if there is a change in the code or when the code breaks, the test script should be able to identify the same without human intervention.
- Timely:
- Testing should follow the Test Driven Development (TDD) approach. Here, the test cases are written before the code is implemented or at least around the same time (and not after!). Hence, if the functionality of the code being tested changes, the respective test cases should change correspondingly.
DSL
Domain Specific Languages (DSLs) are small programming languages that do only a small number of activities within a specific task domain. Thus we can say that a DSL is not general. Examples for DSLs include migration scripts (which are a small set of statements with the sole job of expressing changes in the database schema), Regexes, SQL.
RSpec
RSpec is a testing tool for Ruby [1]. It is based on Behavior Driven Development(BDD) framework and is inspired by JBehave which is another BDD testing framework [2]. RSpec is considered a DSL for writing tests. The notable difference between RSpec and SQL is that, while RSpec is an internal DSL, SQL is stand alone. Internal or embedded DSLs are implemented within another language that acts as their host [3].
Features of RSpec
- Each test in RSpec is called a spec (which is short for specification).
- RSpec code inhabits the Spec directory which mimics the directory structure of the application.rspec:install is a Rails generator that creates the sub-directory structure for the Spec directory.
- Specs are usually written for the controller and model methods. View spec checking is done mostly using the controller spec (seeing that the view will call controller method) and so, specs are usually not written for view. Instead, one can use Cucumber to test the view functionality.
Apps folder | Spec folder |
---|---|
app/models/*.rb | spec/models/*_spec.rb |
app/controllers/ *_controller.rb | spec/controllers/ *_controller_spec.rb |
app/views/*/*.html.erb | Use Cucumber |
User stories are taken as the input to write RSpecs. The following is an example of one such user story:
When I fill in "Search Posts" with "Assignments" And I press "Search" Then I should be on the Posts page with Assignment Posts
Once we have the user stories ready, the next is to implement the corresponding code to realize this test case.
The code we wish we had
When the user clicks on the button in the view for search_posts, the controller action receives the form submission and should perform the following actions:
- It will call a method that searches the BackChannel App for posts with the specified search term(s)
- It then calls the model method to check the database to see if the entered value exists.
- If there is a match, a view with the Posts corresponding to the search terms is rendered. If no match is found, there should be a redirection to the homepage with an error message for the user's information.
The RSpec for the above mentioned scenario can be written as follows:
require 'spec_helper' describe PostController do describe 'searching Posts' do it 'should call the model method that performs Post search' it 'should select the Search Results template for rendering' it 'should make the Post search results available to that template' end end
Spec_helper is a file that RSpec creates as a part of the install step [4]. This file ensures that the functions required for testing are loaded. The behavior of the post controller is described in the code block. The main behavior that we are focusing on is searching post. In the code, it is a method that takes in a string parameter. This string describes the actions to be performed that corresponds to the specification given in the user story. Further behaviors can be added to or nested within the main describe block, or new test scripts can be written, as per requirements.
Summary
A good test case must adhere to the FIRST principle (Fast, Independent, Repeatable, Self-checking, Timely). TDD or Test Driven Development is the approach in which test cases are written for code even before the implementation is realized. DSLs or Domain Specific Languages take on a very specialized set of tasks. When unit tests are written using RSpec, which is an embedded DSL for Ruby testing, we usually write the tests for the controller and model methods and leave the view testing to Cucumber. The Spec files are stored in the Spec directory which mimics the application directory structure. RSpec can be used to perform unit and functional testing.
References
- http://rspec.info/
- http://en.wikipedia.org/wiki/RSpec
- http://en.wikipedia.org/wiki/Domain-specific_language
- http://jeffkreeftmeijer.com/2011/spec-helpers-bundler-setup-faster-rails-test-suites/
Also see
- https://www.youtube.com/watch?v=oFX1KPNRruA&feature=relmfu
- http://en.wikipedia.org/wiki/Software_quality_assurance
- http://en.wikipedia.org/wiki/Test-driven_development
- http://en.wikipedia.org/wiki/Regular_expression
- http://en.wikipedia.org/wiki/SQL
- http://en.wikipedia.org/wiki/Ruby_%28programming_language%29
- http://en.wikipedia.org/wiki/Behavior-driven_development
- http://jbehave.org/
- http://en.wikipedia.org/wiki/Domain-specific_language
- http://guides.rubyonrails.org/command_line.html
- http://en.wikipedia.org/wiki/Cucumber_%28software%29
- http://pastebin.com/kJxjwSF6