{"id":22624621,"url":"https://github.com/barrettotte/sql-unit-poc","last_synced_at":"2025-03-29T03:16:49.153Z","repository":{"id":114091357,"uuid":"170942044","full_name":"barrettotte/SQL-UNIT-POC","owner":"barrettotte","description":"A very basic POC MSSQL unit testing framework using Python and T-SQL. Directory/file driven unit tests using SQL and JSON.","archived":false,"fork":false,"pushed_at":"2019-03-02T02:25:43.000Z","size":84,"stargazers_count":3,"open_issues_count":4,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-03T13:13:15.852Z","etag":null,"topics":["json","mssql","proof-of-concept","python","sql","t-sql","test-runner","unit-testing"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/barrettotte.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-15T23:34:44.000Z","updated_at":"2023-11-28T20:47:38.000Z","dependencies_parsed_at":"2023-06-12T14:00:36.382Z","dependency_job_id":null,"html_url":"https://github.com/barrettotte/SQL-UNIT-POC","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barrettotte%2FSQL-UNIT-POC","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barrettotte%2FSQL-UNIT-POC/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barrettotte%2FSQL-UNIT-POC/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barrettotte%2FSQL-UNIT-POC/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/barrettotte","download_url":"https://codeload.github.com/barrettotte/SQL-UNIT-POC/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246131335,"owners_count":20728303,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","mssql","proof-of-concept","python","sql","t-sql","test-runner","unit-testing"],"created_at":"2024-12-09T00:17:03.933Z","updated_at":"2025-03-29T03:16:49.130Z","avatar_url":"https://github.com/barrettotte.png","language":"Python","readme":"# SQL-UNIT-POC\n\n\nA very basic POC MSSQL unit testing framework using Python and T-SQL. Directory/file driven unit tests using SQL and JSON.\n\n\nDeveloped using Python 3.7 and Microsoft SQL Server 2017. \n\n\n## Example directory structure\n``` text\n./SQL-Unit-POC/SQL-Unit-Tests/\n|-- Basic-SQL-Suite\n|   |-- inner_join\n|   |   |-- inner_join.actual.json\n|   |   |-- inner_join.expected.json\n|   |   |-- inner_join.sql\n|   |-- another_test\n|-- another-suite\n|   |-- some_test\n```\n\n\n## Sample Suite config.json (.\\SQL-Unit-Tests\\Basic-SQL-Suite\\Basic-SQL-Suite.config.json)\n```JSON\n/* NOTE: This will only use current Windows user credentials for now. */\n{\n    \"database-config\": {\n        \"server\": \"BARRETT-MAIN\\\\BARRETTSQL\",\n        \"database\": \"BARRETT_TEST\",\n        \"dialect\": \"MSSQL\"\n    }    \n}\n```\n\n\n## Example SQL Input (inner_join.SQL)\n```SQL\n-- This is a simple test for an INNER JOIN statement --\n\nINSERT INTO developers (username, fav_language) VALUES ('barrettotte', 'Python');\nINSERT INTO developers (username, fav_language) VALUES ('firstlast', 'Java');\nINSERT INTO developers (username, fav_language) VALUES ('helloworld123', 'JavaScript');\nINSERT INTO developers (username, fav_language) VALUES ('someguy1', 'C++');\n\n\nSELECT DISTINCT u.first_name, u.last_name, d.fav_language\nFROM [BARRETT_TEST].[dbo].[developers] AS d\nINNER JOIN [BARRETT_TEST].[dbo].[users] AS u \n\tON u.username = d.username;\n```\n\n\n## Example Expected JSON (inner_join.expected.json)\n```JSON\n{\n    \"success\": \"true\",\n    \"columns\": [\n        {\n            \"name\": \"first_name\",\n            \"type\": \"VARCHAR(50)\"\n        },\n        {\n            \"name\": \"last_name\",\n            \"type\": \"VARCHAR(50)\"\n        },\n        {\n            \"name\": \"fav_language\",\n            \"type\": \"VARCHAR(50)\"\n        }\n    ],\n    \"rows\": [\n        {\n            \"first_name\": \"barrett\",\n            \"last_name\": \"otte\",\n            \"fav_language\": \"Python\"\n        },\n        {\n            \"first_name\": \"hello\",\n            \"last_name\": \"world\",\n            \"fav_language\": \"JavaScript\"\n        }\n    ]\n}\n```\n\n\n## Example console/log output of executing test suite .\\SQL-Unit-Tests\\Basic-SQL-Suite\\\n``` TEXT\n[INFO  2019-03-01 20:47:08.035128] SQL Test Runner initializing\n[INFO  2019-03-01 20:47:08.038142] SQL Test Runner using directory [D:\\Programming\\SQL-UNIT-POC\\SQL-Unit-Tests]\n[INFO  2019-03-01 20:47:08.041107] Loading all test files\n[INFO  2019-03-01 20:47:08.045119] Found 1 suite(s) in [D:\\Programming\\SQL-UNIT-POC\\SQL-Unit-Tests]\n[INFO  2019-03-01 20:47:08.052078] SQL Test Runner targeted with suite [Basic-SQL-Suite]\n[INFO  2019-03-01 20:47:08.055094] Initializing SQLUnit_Wrapper Stored Procedure\n[INFO  2019-03-01 20:47:08.058062] Creating database connection to [BARRETT-MAIN\\BARRETTSQL\\BARRETT_TEST]\n[INFO  2019-03-01 20:47:08.091971] Running suite [Basic-SQL-Suite] with 11 test(s)\n[INFO  2019-03-01 20:47:08.094988]    Running test [create_table]                (1 of 11)\n[INFO  2019-03-01 20:47:08.097956]       Reading files\n[INFO  2019-03-01 20:47:08.100973]       Executing [create_table.sql]\n[INFO  2019-03-01 20:47:08.106931]       SQL Query failed\n[INFO  2019-03-01 20:47:08.112916]       Test Passed\n[INFO  2019-03-01 20:47:08.115933]       Test execution in 17.9279 ms\n.     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .\n.     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .\n.     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .\n[INFO  2019-03-01 20:47:08.162783]    Running test [fail_onpurpose]              (4 of 11)\n[INFO  2019-03-01 20:47:08.165774]       Reading files\n[INFO  2019-03-01 20:47:08.167792]       Executing [fail_onpurpose.sql]\n[INFO  2019-03-01 20:47:08.177765] X      Test Failed\n[INFO  2019-03-01 20:47:08.180734]       Test execution in 14.9822 ms\n[INFO  2019-03-01 20:47:08.184723]    Running test [fail_select]                 (5 of 11)\n[INFO  2019-03-01 20:47:08.187742]       Reading files\n[INFO  2019-03-01 20:47:08.192725]       Executing [fail_select.sql]\n[INFO  2019-03-01 20:47:08.197712]       SQL Query failed\n[INFO  2019-03-01 20:47:08.201678]       Test Passed\n[INFO  2019-03-01 20:47:08.204670]       Test execution in 15.9812 ms\n[INFO  2019-03-01 20:47:08.207662]    Running test [inner_join]                  (6 of 11)\n[INFO  2019-03-01 20:47:08.211651]       Reading files\n[INFO  2019-03-01 20:47:08.214671]       Executing [inner_join.sql]\n[INFO  2019-03-01 20:47:08.226654]       Test Passed\n[INFO  2019-03-01 20:47:08.230601]       Test execution in 18.9922 ms\n.     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .\n.     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .\n.     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .     .\n[INFO  2019-03-01 20:47:08.350281] Results: 10 of 11 test(s) passed\n[INFO  2019-03-01 20:47:08.353300] Suite execution in 261.3287 ms\n[INFO  2019-03-01 20:47:08.356265] Cleaning up database and connection\n[INFO  2019-03-01 20:47:08.367236] SQL Test Runner finished\n```\n\n\n## Sample Suite results JSON (Basic-SQL-Suite.results.json)\n```JSON\n{\n    \"name\": \"Basic-SQL-Suite\",\n    \"total\": 11,\n    \"passed\": 10,\n    \"time\": 261.3287,\n    \"tests\": [ ... All tests with names and paths ... ]\n}\n```\n\n\n## Summary\n* Test suites\n   * A collection of test cases containing {test}.sql, {test}.expected.json, and {test}.actual.json\n   * Each test suite can be configured for different databases/servers in {test-suite}.config.json\n* Test cases\n  * {test}.sql - SQL to execute\n  * {test}.expected.json - expected results (columns, success?, data[])\n  * {test}.actual.json - actual results (columns, success?, data[])\n* Test runner\n    * Launch run.bat / run.sh passing target test suite and config path\n    * Initialize SQL-Unit Test Runner, load all test files\n    * Init SQL-Unit wrapper stored procedure in target database\n    * Loop over all tests within target test collection\n    * Load {test}.expected.json and {test}.sql and pass to SQL-Unit wrapper SP\n    * SQL-Unit wrapper starts T-SQL transaction and saves before execution\n    * {test}.sql is injected into EXEC() command and executed\n    * {test}.sql result-set stored in dynamic TMP table defined by columns in {test}.expected.json\n    * result-set returned to Python side and transaction rollback\n    * Evaluate expected vs actual of {test}.sql\n    * Clean up and Finish\n      * remove SQL-Unit wrapper stored procedure and any TMP tables\n\n\n## Limitations\n* Only tested with Microsoft SQL Server 2017 and Python 3.7\n* Credentials are based on current Windows credentials\n* This was a POC project\n\n\n## Development Notes\n* Python Virtual Environment\n  * Install ```pip install virtualenv```\n  * Init ```cd .\\projectfolder \u0026\u0026 virtualenv venv```\n  * Enter ```venv\\Scripts\\activate```\n  * Exit ```deactivate```\n\n\n## Future Ideas/Improvements\n* Generate Report from test suite results\n* Generate formatted reports with HTML\n* CI / CD using GitLab and Docker for project\n* GitLab build step and/or Jenkins Job using SQLUnit on a test database\n* Deeper performance measurement\n* Generate graphs from test results/performance and add to reports\n* Start experimenting with the possiblity of basic DB2 queries?\n\n\n## References\n* Heavily inspired by IOUnit https://github.com/ioUnit/ioUnit\n* Designed basic SQL tests around these:\n  * http://www.sqlservertutorial.net/sql-server-basics/\n  * https://goalkicker.com/MicrosoftSQLServerBook/\n* https://docs.microsoft.com/en-us/sql/?view=sql-server-2017\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbarrettotte%2Fsql-unit-poc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbarrettotte%2Fsql-unit-poc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbarrettotte%2Fsql-unit-poc/lists"}