2015-08-11 | Leave a comment I’ve finished my previous post a bit too soon and was not precise on the ruby-plsql unite test results analysis. I’ve decided to dig a bit deeper to validate that ruby-plsql (RSpec) actually support datatype mismatch exceptions where utPLSQL unit testing fails due to oracle implicit datatype conversion. Retrospective Lets have a look once more at where we landed. There is a package with two functions. CREATE OR REPLACE PACKAGE some_table_api AS FUNCTION get_customer_no( p_customer_id customers.customer_id%TYPE ) RETURN customers.customer_no%TYPE; FUNCTION get_customer_valid_flag( p_customer_id customers.customer_id%TYPE ) RETURN customers.customer_valid_flag%TYPE; END some_table_api; / The package was initially working on the below table structure. CREATE TABLE customers ( customer_id NUMBER, customer_no NUMBER(10,0), customer_valid_flag VARCHAR2(1), CONSTRAINT chk_valid_flag CHECK (customer_valid_flag IN ('0','1')) ); But the table structure was changed: CREATE TABLE customers_new ( customer_id NUMBER, customer_no VARCHAR2(30), customer_valid_flag NUMBER(1,0) ); INSERT INTO customers_new SELECT * FROM customers; DROP TABLE customers; RENAME customers_new TO customers; and so the datatypes returned by functions have changed. We have following ruby-plsql unit tests. describe 'get customer number' do before(:all) do plsql.customers.insert({customer_id: -1, customer_no: 123456, customer_valid_flag: '1' }) end it 'returns expected customer number as a numeric value' do expect( plsql.some_table_api.get_customer_no(-1) ).to eq 123456 end it 'returns expected customer number as a numeric value through assignment' do result = plsql.some_table_api.get_customer_no(-1) expect( result ).to eq 123456 end end describe 'get customer valid flag' do before(:all) do plsql.customers.insert({customer_id: -1, customer_no: 123456, customer_valid_flag: '1' }) end it 'returns expected customer validity flag as a character' do expect( plsql.some_table_api.get_customer_valid_flag(-1) ).to eq '1' end it 'returns expected customer validity flag as a character through assignment' do result = plsql.some_table_api.get_customer_valid_flag(-1) expect( result ).to eq '1' end end And the tests are now failing. C:\Users\Jacek\RubymineProjects\utplsql_vs_plsql_spec>rspec spec\some_table_api\* FFFF Failures: 1) get customer number returns expected customer number as a numeric value Failure/Error: plsql.customers.insert({customer_id: -1, customer_no: 123456, customer_valid_flag: '1' }) TypeError: can't convert Fixnum into String # ./spec/some_table_api/get_customer_no_spec.rb:4:in `block (2 levels) in <top (required)>' 2) get customer number returns expected customer number as a numeric value through assignment Failure/Error: plsql.customers.insert({customer_id: -1, customer_no: 123456, customer_valid_flag: '1' }) TypeError: can't convert Fixnum into String # ./spec/some_table_api/get_customer_no_spec.rb:4:in `block (2 levels) in <top (required)>' 3) get customer valid flag returns expected customer validity flag as a character Failure/Error: plsql.customers.insert({customer_id: -1, customer_no: 123456, customer_valid_flag: '1' }) TypeError: can't convert Fixnum into String # ./spec/some_table_api/get_customer_valid_flag_spec.rb:4:in `block (2 levels) in <top (required)>' 4) get customer valid flag returns expected customer validity flag as a character through assignment Failure/Error: plsql.customers.insert({customer_id: -1, customer_no: 123456, customer_valid_flag: '1' }) TypeError: can't convert Fixnum into String # ./spec/some_table_api/get_customer_valid_flag_spec.rb:4:in `block (2 levels) in <top (required)>' Finished in 0.025 seconds (files took 1.48 seconds to load) 4 examples, 4 failures Failed examples: rspec ./spec/some_table_api/get_customer_no_spec.rb:7 # get customer number returns expected customer number as a numeric value rspec ./spec/some_table_api/get_customer_no_spec.rb:11 # get customer number returns expected customer number as a numeric value through assignment rspec ./spec/some_table_api/get_customer_valid_flag_spec.rb:7 # get customer valid flag returns expected customer validity flag as a character rspec ./spec/some_table_api/get_customer_valid_flag_spec.rb:11 # get customer valid flag returns expected customer validity flag as a character through assignment C:\Users\Jacek\RubymineProjects\utplsql_vs_plsql_spec> The thing is, the test did not fail because the function return datatype has changed. The tests have actually failed on the insert statement due to the fact that the table structure was changed. That got me thinking. Those little and simple tests already have some dependency to table CUSTOMERS, though the CUSTOMERS table itself is not being tested. The tests should validate API regardless of the table structure. So what can be done? Plain SQL initialization Since it is Ruby that guards datatypes more than Oracle, I can use Oracle to do the inserts and take advantage of the Oracle “feature” of implicit datatype conversion. Let’s give it a try with get_customer_no function describe 'get customer number using pure SQL setup' do before(:all) do plsql.execute <<-SQL INSERT INTO customers(customer_id, customer_no,customer_valid_flag) VALUES (-1, 123456, '1') SQL end it 'returns expected customer number as a numeric value' do expect( plsql.some_table_api.get_customer_no(-1) ).to eq 123456 end it 'returns expected customer number as a numeric value through assignment' do result = plsql.some_table_api.get_customer_no(-1) expect( result ).to eq 123456 end end And the results of tests are: C:\Users\Jacek\RubymineProjects\utplsql_vs_plsql_spec>rspec spec\some_table_api\get_customer_no_pure_sql_spec.rb FF Failures: 1) get customer number using pure SQL setup returns expected customer number as a numeric value Failure/Error: expect( plsql.some_table_api.get_customer_no(-1) ).to eq 123456 expected: 123456 got: "123456" (compared using ==) # ./spec/some_table_api/get_customer_no_pure_sql_spec.rb:11:in `block (2 levels) in <top (required)>' 2) get customer number using pure SQL setup returns expected customer number as a numeric value through assignment Failure/Error: expect( result ).to eq 123456 expected: 123456 got: "123456" (compared using ==) # ./spec/some_table_api/get_customer_no_pure_sql_spec.rb:16:in `block (2 levels) in <top (required)>' Finished in 0.03701 seconds (files took 1.75 seconds to load) 2 examples, 2 failures Failed examples: rspec ./spec/some_table_api/get_customer_no_pure_sql_spec.rb:10 # get customer number using pure SQL setup returns expected customer number as a numeric value rspec ./spec/some_table_api/get_customer_no_pure_sql_spec.rb:14 # get customer number using pure SQL setup returns expected customer number as a numeric value through assignment C:\Users\Jacek\RubymineProjects\utplsql_vs_plsql_spec> After overcoming the tests failure on COUSTOMERS table, the tests are still failing. The tests have failed on the assertions, as they should. We expected to get an integer and received a string since the datatypes of functions have changed. Cool!