plsql_unit_test 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -0,0 +1,153 @@
1
+ # PLSQL Unit Test
2
+
3
+ This gem is intended to be used to test PLSQL code. Most of the test framework is provided by Test::Unit, and this gem simply adds a few convenience methods that are useful when unit testing PLSQL code.
4
+
5
+ # Dependencies
6
+
7
+ This gem depends on:
8
+
9
+ * [SimpleOracleJDBC](http://rubygems.org/gems/simpleOracleJDBC) to provide a JDBC interface to Oracle
10
+ * [Data_Factory](http://rubygems.org/gems/data_factory) to provide an mechanism for generating test data
11
+ * The Oracle ojdbc6.jar drivers should be in the jruby lib directory
12
+
13
+ The gem also requires JRuby, mostly because SimpleOracleJDBC requires JRuby. It would be possible to make it run in MRI Ruby, but a different database interface would be required, using perhaps OCI8.
14
+
15
+ # How to Create a PLSQL Unit Test Suite
16
+
17
+ ## Test Helper
18
+
19
+ First, create a new directory for the tests. Then create a file called test_helper.rb, it should contain something like the following:
20
+
21
+ require 'rubygems'
22
+ require 'plsql_unit_test'
23
+
24
+ PLSQLUnitTest::Setup.connect('sodonnel', # user
25
+ 'sodonnell', # password
26
+ 'local11gr2.world', # service
27
+ 'localhost', # IP address
28
+ '1521') # port
29
+
30
+ This code does two things. It loads the plsql\_unit\_test gem (which also requires SimpleOracleJDBC and data_factory), and then establishes a database interface / connection. The database interface is provided by an instance of SimpleOracleJDBC::Interface - check out the documentation of SimpleOracleJDBC to understand how to use it.
31
+
32
+ This single database interface is shared across all the test classes in the test suite. It is actually stored in a class instance variable called @@db_interface within the Test::Unit::TestCase class.
33
+
34
+ ## Creating a Test
35
+
36
+ The test framework is all provided by Test::Unit, so tests can be coded in exactly the same way as usual - have a look at the Test::Unit documentation to learn about all the features of Test::Unit. An example of a very simple test is as follows:
37
+
38
+ require './test_helper'
39
+
40
+ class FirstTest < Test::Unit::TestCase
41
+
42
+ def setup
43
+ end
44
+
45
+ def teardown
46
+ end
47
+
48
+ def test_db_connection_works
49
+ query = @@db_interface.execute_sql("select 1 from dual")
50
+ results = query.all_array
51
+
52
+ assert_equal(1, results.length, 'There should be one row in the result set')
53
+ assert_equal(1, results[0][0], 'The first and only row in the result set should contain the value 1')
54
+ end
55
+
56
+ end
57
+
58
+ There are two important points:
59
+
60
+ * Notice that the test_helper file is required as the first line of code. This is important as it connects to the database and loads the other required modules.
61
+ * The variable @@db_interface is available for database interactions
62
+
63
+ ## Running a Test
64
+
65
+ As with simple Test::Unit test suites, tests can be executed by simply passing the test filename to JRuby:
66
+
67
+ $ jruby first_test_test.rb
68
+ Run options:
69
+
70
+ # Running tests:
71
+
72
+ .
73
+
74
+ Finished tests in 0.125000s, 8.0000 tests/s, 16.0000 assertions/s.
75
+
76
+ 1 tests, 2 assertions, 0 failures, 0 errors, 0 skips
77
+
78
+ ## Test Runner
79
+
80
+ Ideally, there should be one Ruby test class for each PLSQL procedure, function or package under test. In a large application there could be many files, so there needs to be a way to run all the tests in the suite. Create a file called test_runner.rb in the same directory as the tests, and put the following code in it:
81
+
82
+ current_dir = File.expand_path(File.dirname(__FILE__))
83
+
84
+ # Find all files that end in _test.rb and require them ...
85
+ files = Dir.entries(current_dir).grep(/^[^#].+_test\.rb$/).sort
86
+ files.each do |f|
87
+ require File.join(current_dir, f)
88
+ end
89
+
90
+ Now all the test files in the directory can be executed with a single command:
91
+
92
+ $ jruby test_runner.rb
93
+
94
+ For this code to work, all files that contain tests should have filenames that end in _test.rb.
95
+
96
+ # Additional Methods in Test::Unit::TestCase
97
+
98
+ PLSQL\_Unit\_Test adds a few extra methods to Test::Unit.
99
+
100
+ ## Assert Methods
101
+
102
+ When testing database code, it can be useful to ensure a given table has zero, one or a number of rows for a given where clause.
103
+
104
+ To assert the users table has a single row for the username foouser:
105
+
106
+ assert_table_has_one_row("users",
107
+ "where username = 'foouser',
108
+ "Ensure the users table has a single row")
109
+
110
+ Similarly, to ensure the users table does not have a row:
111
+
112
+ assert_table_has_zero_rows("users",
113
+ "where username = 'foouser',
114
+ "Ensure the users table zero rows")
115
+
116
+ Finally, to check a table has a given number of rows:
117
+
118
+ assert_table_has_zero_rows("users",
119
+ 10
120
+ "where status = 'locked'
121
+ "Ensure 10 users are locked")
122
+
123
+ ## Set The Database Interface
124
+
125
+ An additional class method is available on Test::Unit::TestCase called set_db_interface. This stores the passed in object in @@db_interface. As this is a class variable, it is shared by all classes that sub-class Test::Unit::TestCase.
126
+
127
+ Test::Unit::TestCase.set_db_interface(my_db_interface)
128
+
129
+ ## Oracle Dates and Times
130
+
131
+ Two further helper methods are available to format a Ruby Time object as an Oracle to_date string:
132
+
133
+ # Return a string representing the passed in Time object
134
+ # as an Oracle to_date string, down to the second
135
+ def time_as_oracle_dtm(time)
136
+ "to_date('#{time.strftime('%Y%m%d %H:%M:%S')}', 'YYYYMMDD HH24:MI:SS')"
137
+ end
138
+
139
+ # Return a string representing the passed in Time object
140
+ # as an Oracle to_date string, down to the day
141
+ def time_as_oracle_dt(time)
142
+ "to_date('#{time.strftime('%Y%m%d')}', 'YYYYMMDD')"
143
+ end
144
+
145
+ # The Setup Class
146
+
147
+ The only other class in PLSQL\_Unit\_Test is the setup class, and it contains a single class method:
148
+
149
+ def self.connect(user, password, service, host, port)
150
+ # ...
151
+ end
152
+
153
+ It takes the given parameters, creates an instance of SimpleOracleJDBC and passes it to both Test::Unit::TestCase and DataFactory::Base via their set_database_interface methods.
data/Rakefile.rb ADDED
@@ -0,0 +1,30 @@
1
+ desc "Generate RDoc"
2
+ task :doc => ['doc:generate']
3
+
4
+ namespace :doc do
5
+ project_root = File.expand_path(File.dirname(__FILE__))
6
+ doc_destination = File.join(project_root, 'doc')
7
+
8
+ begin
9
+ require 'yard'
10
+ require 'yard/rake/yardoc_task'
11
+
12
+ YARD::Rake::YardocTask.new(:generate) do |yt|
13
+ yt.files = Dir.glob(File.join(project_root, 'lib/**/*.rb')) + #, '**', '*.rb')) +
14
+ [ File.join(project_root, 'README.md') ]
15
+ puts yt.files
16
+ yt.options = ['--output-dir', doc_destination, '--readme', 'README.md']
17
+ end
18
+ rescue LoadError
19
+ desc "Generate YARD Documentation"
20
+ task :generate do
21
+ abort "Please install the YARD gem to generate rdoc."
22
+ end
23
+ end
24
+
25
+ desc "Remove generated documenation"
26
+ task :clean do
27
+ rm_r doc_dir if File.exists?(doc_destination)
28
+ end
29
+
30
+ end
@@ -1,5 +1,13 @@
1
1
  module PLSQLUnitTest
2
2
  class Setup
3
+
4
+ # Establishes a database connection using the SimpleOracleJDBC::Interface
5
+ # class. This interface is then passed to both Test::Unit::TestCase
6
+ # and DataFactory::Base using their set_database_interface methods.
7
+ #
8
+ # After calling this method, the class instance variable @@db_interface
9
+ # will be available in all sub-classes of Test::Unit::TestCase and can
10
+ # be used for database interactions.
3
11
  def self.connect(user, password, service, host, port)
4
12
  interface = SimpleOracleJDBC::Interface.create(user,
5
13
  password,
@@ -1,18 +1,53 @@
1
1
  class Test::Unit::TestCase
2
2
 
3
-
3
+ # Sets the class instance variable @@db_interface to the
4
+ # object that is passed in
4
5
  def self.set_database_interface(interface)
5
6
  @@db_interface = interface
6
7
  end
7
8
 
9
+ # Used to assert / test a given table has only a single row.
10
+ # If a where clause is passed, it should start with 'where'. The table
11
+ # name and where clause are used to form a select statement in the form:
12
+ #
13
+ # "select count(*) from #{table} #{where_clause}"
14
+ #
15
+ # @example Assert the users table has a single row for user foouser
16
+ # assert_table_has_one_row('users',
17
+ # "where username = 'foouser'",
18
+ # "Ensure the users table has a single row")
19
+ #
8
20
  def assert_table_has_one_row(table, where_clause=nil, message=nil)
9
21
  assert_table_has_many_rows(table, 1, where_clause, message)
10
22
  end
11
23
 
24
+ # Used to assert / test a given table has zero rows.
25
+ # If a where clause is passed, it should start with 'where'. The table
26
+ # name and where clause are used to form a select statement in the form:
27
+ #
28
+ # "select count(*) from #{table} #{where_clause}"
29
+ #
30
+ # @example Assert the users table has zero rows for user foouser
31
+ # assert_table_has_zero_rows('users',
32
+ # "where username = 'foouser'",
33
+ # "Ensure the users table has zero rows")
34
+ #
12
35
  def assert_table_has_zero_rows(table, where_clause=nil, message=nil)
13
36
  assert_table_has_many_rows(table, 0, where_clause, message)
14
37
  end
15
38
 
39
+ # Used to assert / test a given table has a given number of rows.
40
+ # If a where clause is passed, it should start with 'where'. The table
41
+ # name and where clause are used to form a select statement in the form:
42
+ #
43
+ # "select count(*) from #{table} #{where_clause}"
44
+ #
45
+ # @example Assert the users table has zero rows for user foouser
46
+ # assert_table_has_many_rows('users',
47
+ # 10
48
+ # "where status = 'locked'",
49
+ # "Ensure the users table has 10 locked rows")
50
+ #
16
51
  def assert_table_has_many_rows(table, row_count, where_clause=nil, message=nil)
17
52
  results = @@db_interface.execute_sql("select count(*) from #{table} #{where_clause}").all_array
18
53
  message = build_message(message, "A count of <?> was expected but was <?> for <?> <?>", row_count.to_s, results[0][0].to_i, table, where_clause)
@@ -21,10 +56,14 @@ class Test::Unit::TestCase
21
56
  end
22
57
  end
23
58
 
59
+ # Returns a string representing an Ruby Time object in Oracle to_date
60
+ # format, accurate to a second.
24
61
  def time_as_oracle_dtm(time)
25
62
  "to_date('#{time.strftime('%Y%m%d %H:%M:%S')}', 'YYYYMMDD HH24:MI:SS')"
26
63
  end
27
64
 
65
+ # Returns a string representing an Ruby Time object in Oracle to_date
66
+ # format, accurate to a day.
28
67
  def time_as_oracle_dt(time)
29
68
  "to_date('#{time.strftime('%Y%m%d')}', 'YYYYMMDD')"
30
69
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plsql_unit_test
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,14 +9,14 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-04 00:00:00.000000000 Z
12
+ date: 2013-03-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: data_factory
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - '='
19
+ - - ! '>='
20
20
  - !ruby/object:Gem::Version
21
21
  version: 0.1.2
22
22
  type: :runtime
@@ -24,7 +24,7 @@ dependencies:
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
- - - '='
27
+ - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: 0.1.2
30
30
  - !ruby/object:Gem::Dependency
@@ -32,7 +32,7 @@ dependencies:
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
- - - '='
35
+ - - ! '>='
36
36
  - !ruby/object:Gem::Version
37
37
  version: 0.1.1
38
38
  type: :runtime
@@ -40,7 +40,7 @@ dependencies:
40
40
  version_requirements: !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
- - - '='
43
+ - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: 0.1.1
46
46
  description: Monkey patches Test::Unit::TestCase to add some additional assert methods,
@@ -55,6 +55,7 @@ files:
55
55
  - lib/plsql_unit_test/setup.rb
56
56
  - lib/plsql_unit_test/test_unit_patch.rb
57
57
  - lib/plsql_unit_test.rb
58
+ - Rakefile.rb
58
59
  - README.md
59
60
  homepage: http://betteratoracle.com
60
61
  licenses: []