Unit Testing - sgml/signature GitHub Wiki

Testing Styles

1. Tests Written First

Pros

  • Forces early clarity of behavior and requirements
  • Strong design pressure → smaller, more modular units
  • Prevents over‑engineering by constraining scope
  • Creates a safety net before implementation begins
  • Encourages decoupling and testability
  • Supports safe, aggressive refactoring

Cons

  • Slows initial development velocity
  • High churn when requirements are unstable
  • Can lead to overly granular or implementation‑focused tests
  • Rigid workflow that some teams find unnatural
  • Difficult for UI, integration, or exploratory work
  • Requires discipline to maintain test quality

2. Tests Written in Tandem (Co‑Evolution)

Pros

  • Balanced approach: speed + discipline
  • Natural workflow for most developers
  • Supports exploratory or evolving domains
  • Tests tend to reflect behavior rather than internals
  • Less churn than strict TDD
  • Reduces risk of over‑specifying behavior too early

Cons

  • Weaker design pressure than tests‑first
  • Easy to drift into “tests last” without discipline
  • Tests may accidentally mirror implementation details
  • Requires intentionality to maintain separation of concerns
  • Can produce inconsistent test coverage if not monitored

3. Tests Written Last (Post‑Hoc Testing)

Pros

  • Fastest initial development
  • Useful for spikes, prototypes, and unknown domains
  • Practical for legacy code where behavior must be discovered
  • Good for UI or integration layers where structure emerges late
  • Allows developers to focus on solving the problem first

Cons

  • Highest risk of untestable, tightly coupled code
  • Tests often shallow, incomplete, or missing edge cases
  • More bugs escape into production
  • Refactoring becomes risky without a safety net
  • Coverage suffers under time pressure
  • Encourages testing “happy paths” only

4. Literate Programming with Inline Assertions

Pros

  • Executable documentation: narrative + correctness in one place
  • Tight coupling between explanation and behavior
  • Excellent for algorithms, invariants, and domain‑heavy logic
  • Reduces brittleness because assertions live near the logic
  • Improves onboarding by exposing intent directly
  • Encourages clarity of reasoning and explicit invariants

Cons

  • Does not scale well across large systems or multi‑module architectures
  • Noisy when code, tests, and documentation coexist in one file
  • Harder to test cross‑cutting concerns (HTTP, DI, transactions)
  • Requires discipline to keep narrative accurate as code evolves
  • Tooling support varies; not all ecosystems treat inline assertions as first‑class tests
  • Can blur separation of concerns between testing and implementation

Summary Comparison Table

Approach Primary Author URL Strengths Weaknesses Best For
Tests First (TDD) Kent Beck https://en.wikipedia.org/wiki/Test-driven_development Strong design pressure; clear intent; safe refactoring; prevents over‑engineering Slower start; rigid; churny when requirements shift Stable domains; backend logic; pure functions
Tests in Tandem Brian Marick http://www.exampler.com/old-blog/2003/08/21/ Balanced; flexible; natural flow; good for evolving systems Less design pressure; risk of drifting into tests‑last Most modern teams; iterative product development
Tests Last Glenford Myers https://en.wikipedia.org/wiki/The_Art_of_Software_Testing Fastest prototyping; good for spikes and legacy discovery Risky; brittle; low coverage; untestable code Legacy code; UI spikes; exploratory work
Literate + Inline Assertions Donald Knuth https://en.wikipedia.org/wiki/Literate_programming Executable documentation; tight intent; great clarity for invariants Doesn’t scale; noisy; limited to logic‑level testing Algorithms; domain logic; teaching; invariants

Testing pyramid

Mocking
├── Code Smell
│   ├── Fix → mock less by rewriting broken code parts carefully
│   ├── One job → mock less when each class does one single clear task
│   └── Contract → mock only when a clear rule guides how parts connect
├── Need
│   ├── Outside → mock calls to systems that live far away from your code
│   ├── Slow → mock long waiting steps with quick fake responses instead
│   └── Vendor → mock a supplier that charges money every time you use it
└── Overlap
    ├── Cap → mock only a few tests instead of spreading into every single case
    ├── Check → mock results but confirm them against the real system sometimes
    └── Act → mock only what the program actually does in daily practice

Fallbacks (alternative to mocking)
├── Defaults → use safe default values instead of trying to mock every missing input
├── Retries → retry failed calls instead of building mocks that hide real errors
└── Cache → serve cached data instead of mocking responses that should come from storage

TDD Process

+------------------------------------------------------+
| Generate TDD tests from comments                     |
+-------------------------------v----------------------+
                |  (TDD: coined by Kent Beck) 
                v
+------------------------------------------------------+
| Run failing tests                                     |
+-------------------------------v----------------------+
                |  ("failing tests": popularized by Extreme Programming, Kent Beck)
                v
+------------------------------------------------------+
| Checkin failing tests                                 |
+-------------------------------v----------------------+
                |  ("checkin": version control terminology emerging from early SCCS/RCS communities)
                v
+------------------------------------------------------+
| Copy/paste code                                       |
+-------------------------------v----------------------+
                |  ("copy/paste": originated with Larry Tesler & early Xerox PARC UI work)
                v
+------------------------------------------------------+
| Lint code                                             |
+-------------------------------v----------------------+
                |  ("lint": invented by Stephen C. Johnson at Bell Labs, 1978)
                v
+------------------------------------------------------+
| Format code                                           |
+-------------------------------v----------------------+
                |  ("format code": early Unix tools like `indent`, 1970s AT&T Bell Labs)
                v
+------------------------------------------------------+
| Create mocks to make TDD tests pass                   |
+------------------------------------------------------+
                |  ("mocks": formalized by Tim Mackinnon, Steve Freeman, Philip Craig, 2000)

SQL Testing

1. Static SQL Analysis (Beyond Linting)

1.1. SQLFluff

GitHub: https://github.com/sqlfluff/sqlfluff
Dialect‑aware SQL static analysis:

  • Structural validation
  • Invalid references (columns, tables)
  • CTE and alias correctness
  • Cross‑dialect normalization

1.2. SQLGlot

GitHub: https://github.com/tobymao/sqlglot
SQL parser + transpiler + validator:

  • AST parsing
  • SQL normalization
  • Structural correctness checks
  • Dialect translation

1.3. pg_query

GitHub: https://github.com/pganalyze/pg_query
PostgreSQL native parser:

  • Converts SQL into PostgreSQL parse tree
  • Validates syntax without execution
  • Useful for static analysis and query‑shape testing

2. Query Plan Testing (Explain‑Only, No Execution)

2.1. pgMustard

GitHub: https://github.com/pganalyze/pg-mustard
EXPLAIN plan analyzer:

  • Detects missing indexes
  • Detects inefficient join orders
  • Highlights sequential scans
  • No query execution required

2.2. pev2 (Dalibo EXPLAIN Visualizer)

GitHub: https://github.com/dalibo/pev2
EXPLAIN JSON parser:

  • Highlights performance anti‑patterns
  • Detects plan regressions
  • Visualizes plan structure

3. Migration Testing (Schema‑Only Validation)

3.1. Sqitch

GitHub: https://github.com/sqitchers/sqitch
Migration dependency graph validator:

  • Validates migration order
  • Detects missing dependencies
  • Ensures reversible migrations

3.2. Atlas

GitHub: https://github.com/ariga/atlas
Schema diff + migration planning:

  • Detects destructive changes
  • Enforces schema invariants
  • Validates migration correctness

3.3. Flyway

GitHub: https://github.com/flyway/flyway
Migration integrity tool:

  • Detects schema drift
  • Validates migration ordering
  • Ensures migration consistency

4. Schema Validation Tools (Structure‑Level Testing)

4.1. pg_validate

GitHub: https://github.com/ankane/pg_validate
PostgreSQL schema validator:

  • Validates foreign keys
  • Validates constraints
  • Validates indexes
  • Validates column types

4.2. SchemaCrawler

GitHub: https://github.com/schemacrawler/SchemaCrawler
Schema inspection + rule enforcement:

  • Detects missing PKs, FKs, indexes
  • Enforces naming conventions
  • Generates schema diagrams

5. Property‑Based SQL Testing (Static or Mocked Execution)

5.1. HypoPG

GitHub: https://github.com/HypoPG/hypopg
Hypothetical index testing:

  • Test index effects without creating indexes
  • Predict performance changes
  • Useful for “what‑if” analysis

5.2. SQLSmith

GitHub: https://github.com/anse1/sqlsmith
Random SQL generator:

  • Tests parser robustness
  • Finds edge‑case SQL bugs
  • Does not require application execution

6. Mutation Testing for SQL

6.1. Mutant

GitHub: https://github.com/mbj/mutant
Mutation testing framework:

  • Mutates SQL expressions
  • Ensures tests detect incorrect SQL
  • Used heavily in Ruby/Sequel ecosystems

6.2. pgTAP

GitHub: https://github.com/theory/pgtap
PostgreSQL unit testing framework:

  • Tests functions, triggers, constraints
  • Supports mutation‑style testing
  • Runs inside PostgreSQL

7. SQL AST / Contract Testing Tools

7.1. jOOQ Parser

GitHub: https://github.com/jOOQ/jOOQ
SQL AST validator:

  • Parses SQL into AST
  • Validates SQL structure
  • Ensures dialect correctness

7.2. sqlcheck

GitHub: https://github.com/jarulraj/sqlcheck
SQL anti‑pattern detector:

  • Detects performance anti‑patterns
  • Detects structural issues
  • No execution required

Summary Table

Category Tool GitHub URL
Static SQL Analysis SQLFluff https://github.com/sqlfluff/sqlfluff
Static SQL Analysis SQLGlot https://github.com/tobymao/sqlglot
Static SQL Analysis pg_query https://github.com/pganalyze/pg_query
Query Plan Testing pgMustard https://github.com/pganalyze/pg-mustard
Query Plan Testing pev2 https://github.com/dalibo/pev2
Migration Testing Sqitch https://github.com/sqitchers/sqitch
Migration Testing Atlas https://github.com/ariga/atlas
Migration Testing Flyway https://github.com/flyway/flyway
Schema Validation pg_validate https://github.com/ankane/pg_validate
Schema Validation SchemaCrawler https://github.com/schemacrawler/SchemaCrawler
Property‑Based SQL Testing HypoPG https://github.com/HypoPG/hypopg
Property‑Based SQL Testing SQLSmith https://github.com/anse1/sqlsmith
Mutation Testing Mutant https://github.com/mbj/mutant
Mutation Testing pgTAP https://github.com/theory/pgtap
SQL AST / Contract Testing jOOQ Parser https://github.com/jOOQ/jOOQ
SQL Anti‑Pattern Detection sqlcheck https://github.com/jarulraj/sqlcheck

Python Testing

Python Testing Methods (Tool‑Backed Only, With GitHub URLs)

This document lists only Python‑specific testing methods that have real, widely‑used tools, excluding:

  • AST validation
  • Formal methods
  • Package/build validation

1. Static Analysis (Beyond Linting)

1.1. MyPy (Static Type Checking)

GitHub: https://github.com/python/mypy
Static type checker for Python:

  • Detects type errors without running code
  • Validates function signatures
  • Enforces type contracts
  • Supports gradual typing

1.2. Pyright (Fast Type Checker)

GitHub: https://github.com/microsoft/pyright
High‑performance static type checker:

  • Detects type mismatches
  • Validates generics, overloads, protocols
  • Editor‑integrated

1.3. Pyre (Meta’s Static Analyzer)

GitHub: https://github.com/facebook/pyre-check
Advanced static analysis:

  • Type checking
  • Taint analysis
  • Security‑focused static checks

2. Security‑Focused Static Analysis (SAST)

2.1. Bandit

GitHub: https://github.com/PyCQA/bandit
Security static analyzer:

  • Detects insecure patterns
  • Hardcoded secrets
  • Unsafe function usage
  • Injection vulnerabilities

2.2. Semgrep

GitHub: https://github.com/semgrep/semgrep
Pattern‑based static analysis:

  • Security rules
  • Code correctness rules
  • Custom rule authoring

3. Property‑Based Testing

3.1. Hypothesis

GitHub: https://github.com/HypothesisWorks/hypothesis
Property‑based testing:

  • Generates thousands of randomized inputs
  • Shrinks failing examples
  • Tests invariants, not examples

4. Mutation Testing (Tests the Tests)

4.1. Mutmut

GitHub: https://github.com/boxed/mutmut
Mutation testing:

  • Mutates Python code
  • Ensures tests detect incorrect behavior
  • Measures test suite strength

4.2. Cosmic Ray

GitHub: https://github.com/sixty-north/cosmic-ray
Mutation testing framework:

  • Parallel mutation execution
  • Configurable operators
  • CI‑friendly

5. Static Contract Checking

5.1. Deal (Design‑by‑Contract for Python)

GitHub: https://github.com/life4/deal
Contract enforcement:

  • Pre/post conditions
  • Invariants
  • Static contract validation
  • Optional runtime checks

6. Documentation‑Driven Testing

6.1. Doctest (Python Standard Library)

GitHub (CPython):
https://github.com/python/cpython/tree/main/Lib/doctest
Executable documentation:

  • Tests embedded in docstrings
  • Ensures examples stay correct
  • Lightweight correctness checking

7. Dependency Security Scanning

7.1. Safety

GitHub: https://github.com/pyupio/safety
Dependency vulnerability scanner:

  • Checks installed packages against CVE database
  • No code execution required

7.2. Pip‑Audit

GitHub: https://github.com/pypa/pip-audit
Official PyPA vulnerability scanner:

  • Audits Python environments
  • Detects vulnerable dependencies

Summary Table

Category Tool GitHub URL
Static Analysis MyPy https://github.com/python/mypy
Static Analysis Pyright https://github.com/microsoft/pyright
Static Analysis Pyre https://github.com/facebook/pyre-check
Security SAST Bandit https://github.com/PyCQA/bandit
Security SAST Semgrep https://github.com/semgrep/semgrep
Property‑Based Testing Hypothesis https://github.com/HypothesisWorks/hypothesis
Mutation Testing Mutmut https://github.com/boxed/mutmut
Mutation Testing Cosmic Ray https://github.com/sixty-north/cosmic-ray
Contract Checking Deal https://github.com/life4/deal
Documentation‑Driven Doctest https://github.com/python/cpython/tree/main/Lib/doctest
Dependency Security Safety https://github.com/pyupio/safety
Dependency Security Pip‑Audit https://github.com/pypa/pip-audit

Eiffel Design by Contract Testing

Testing in Eiffel

Testing in Eiffel is primarily based on the Design by Contract (DbC) methodology, which integrates testing directly into the software development process. Here's how it works and what makes it unique:

How Testing is Done in Eiffel:

  1. Preconditions: These define the conditions that must be true before a method is executed. If the precondition is violated, an exception is raised.
  2. Postconditions: These define the conditions that must be true after a method has executed. If the postcondition is violated, an exception is raised.
  3. Class Invariants: These define conditions that must always be true for all instances of a class. They are checked at the beginning and end of every method call to ensure consistency.

Unique Aspects of Testing in Eiffel:

  • Automatic Testing: EiffelStudio, the integrated development environment for Eiffel, includes tools like AutoTest that automatically generate tests based on the contracts defined in the code.
  • Continuous Contract Checking: Eiffel's runtime system continuously checks contracts (preconditions, postconditions, and invariants) during execution, ensuring that the software adheres to its specifications at all times.
  • Regression Testing: The suite of tests can be run at any time to ensure that changes or additions to the code do not break existing functionality.

Eiffel Leap Year Test

Design Contract

class
    DATE

create
    make

feature -- Initialization
    make (a_day, a_month, a_year: INTEGER)
        do
            day := a_day
            month := a_month
            year := a_year
        end

feature -- Access
    day: INTEGER
    month: INTEGER
    year: INTEGER

feature -- Date Manipulation
    to_string: STRING
        do
            Result := day.out + "/" + month.out + "/" + year.out
        end

feature -- Leap Year Check
    is_leap_year (a_year: INTEGER): BOOLEAN
            -- Check if the given year is a leap year
        require
            valid_year: a_year > 0
        do
            if a_year \\ 4 = 0 then
                if a_year \\ 100 /= 0 or else a_year \\ 400 = 0 then
                    Result := True
                else
                    Result := False
                end
            else
                Result := False
            end
        ensure
            correct_result: (Result = ((a_year \\ 4 = 0) and then ((a_year \\ 100 /= 0) or else (a_year \\ 400 = 0))))
        end

invariant
    valid_day: day > 0 and day <= 31
    valid_month: month > 0 and month <= 12
    valid_year: year > 0

end

Test Class

class
    DATE_LEAP_YEAR_CHECK

create
    make

feature -- Initialization
    make
        local
            a_date: DATE
        do
            create a_date.make (15, 1, 2025)
            print (a_date.to_string + "%N")
            if a_date.is_leap_year (2024) then
                print ("2024 is a leap year.%N")
            else
                print ("2024 is not a leap year.%N")
            end

            -- Test invalid year (should fail precondition)
            -- print (a_date.is_leap_year (-1))  -- Uncommenting this line will raise a precondition violation

            -- Test the correct result postcondition
            assert ("2024 should be a leap year", a_date.is_leap_year (2024) = True)
            assert ("2023 should not be a leap year", a_date.is_leap_year (2023) = False)
        end

feature -- Assertion
    assert (description: STRING; condition: BOOLEAN)
        do
            if not condition then
                print (description + " failed.%N")
            else
                print (description + " passed.%N")
            end
        end

end

References

Testing import statements

import unittest

class TestImport(unittest.TestCase):
    def test_import(self):
        with self.assertRaises(ImportError):
            import non_existent_module

if __name__ == '__main__':
    unittest.main()

The way unit testing works you have to take the entire engine apart and put it back multiple time until you find where the weird noise is coming from.

The way integration testing works you have to swap old parts for new parts and see if the engine sounds the same with either one.

The way end-to-end testing you need to turn the key and drive around the block.

Avoid adding tests which may return false positives or false negatives in the future. To do this, prefer tests based on numbers rather than complex boolean logic.

Mockgen: var mock = 'window.name'.replace('.', '":{"').replace(/^/,'{"').replace(/$/,'":""}}')

Stubgen: function foo(value){ return /.=.=>.{/.exec(value) ? /.*=>.{/.exec(value).toString() : false} function bar(value){ return value } function baz(value){ return String("SearchViewModel." + value).trim().replace(/[\s=>{}]/g,"")} var arrows = document.querySelector("pre").innerText.split("\n").map(foo).filter(bar) var stubs = arrows.map(baz) window.stubs = stubs;

Installing Jasmine standalone

Download the latest Jasmine release from the Jasmine release page:

Running Jasmine locally

  1. Run Jasmine in the browser by downloading the zip file, extracting it, the referencing the files as follows:
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/jasmine.js"></script>
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/jasmine-html.js"></script>
<script type="text/javascript" src="jasmine/lib/jasmine-2.0.0/boot.js"></script>

Installing Jasmine using npm (Node Package Manager)

  1. Set up project directory for Jasmine

    Create a folder and run npm init this will create an empty package.json file and will ask some questions about your project to fill project json file.

    Add 2 directories app - for the Server and spec - for tests

  2. Get Jasmine

    From root project directory run

    npm install jasmine-node --save

    npm install request --save

    npm install express --save

    this will get you the packages

    ./node_packages/.bin/jasmine-node spec will run jasmine binary

    After this your package.json should look similar to this

    package.json file, after which that file should look like this:

    { "name": "Jasmine", "version": "0.0.1", "description": "Jasmine", "main": "index.js", "scripts": { "test": "./node_modules/.bin/jasmine-node spec" }, "author": "Me", "license": "ISC" }

Install with npm

npm install -g jasmine

If being used with karma, install karma-jasmine

npm install --save-dev karma-jasmine

METHODOLOGY

BDD # Before any coding starts, encapsulate each user behavior into a set of tests # Within each set, write a test against an object or method which represents a unit of business logic # Run the test. The test fails because there isn’t any code in place to support the code # Write some code to make the tests pass # Run the tests # Refactor the code # Test again and fix bugs and implementation # Reorganize or add new sets of tests as user behaviors are clarified
TDD # Before any coding starts, write a test against an object or method which represents a unit of business logic # Run the test. The test fails because there isn’t any code in place to support the code. # Write some code to make the tests pass # Run the tests # Refactor the code # Test again and fix bugs and implementation
QA Driven Unit Testing # Write some code # QA finds a bug # Write a test to make the code fail # Refactor the code # Run the test

SETUP

Jasmine # download the standalone distribution zip file # edit an existing html file # add jasmine.js, boot.js, and jasmine-html.js <script> tags # add jasmine.css tag # add your source files as separate <script> tags # add your spec files as separate <script> tags # open the SpecRunner.html file to run your tests # add source and spec <script> tags to add more tests
jQuery # download qunit.js and qunit.css # edit an existing html file # add #qunit and #qunit-fixture divs to a html file # add qunit.js <script> tag # add qunit.css tag # open the html file to run your tests # use module() to add more tests

ARCHITECTURE

Jasmine # /test/lib/jasmine/jasmine.js # /test/lib/jasmine/jasmine.css # /test/lib/jasmine/jasmine-html.js # /test/lib/jasmine/boot.js # /test/src/foo.js # /test/spec/fooSpec.js # /test/SpecRunner.html
QUnit # /test/lib/qunit/qunit.css # /test/lib/qunit/qunit.js # /test/src/foo.js # /test/qunitrunner.html

Common Assertions

Jasmine
toBeDefined
toBeTruthy
toBeFalsy
toThrow
toBe
toEqual
QUnit
ok
equal
notEqual
raises
deepEqual
strictEqual
Purpose
to test if something is not undefined
to test if two primitive values are equal
to test if two primitive values are not equal
to test if a callback throws an exception
to test if two objects are the same
to test if two primitive values are equal and the same type

FEATURE COMPARISON

Jasmine # Dependency injection via spies ## inject mock data from a call ## inject properties and functions ## overwrite a function for your test purposes ## fake AJAX ### andCallFake() # custom assertions ## jasmine.addMatchers() # Config API ## boot.js includes all public methods and global settings # Logging API ## console.js includes logging methods ## console.log can be captured to emulate spy feature of Jasmine # BDD assertions ## toMatch ## toBeDefined ## toBeUndefined ## toBeNull ## toContain ## toBeLessThan ## toBeGreaterThan # Mock time ## jasmine.Clock.tick() can emulate time specific behaviors # Type Assertions ## jasmine.any can emulate typeOf checks # Spies ## spy can replace console.log to record method calls within a function ## spies can stub window method calls within a function # Documentation ## The test file reads like documentation and describes everything the user can do # Reporting ## jsApiReporter() receives a copy of spec results, and is used extract the data
QUnit # Dependency injection via extend ## inject mock data from a call # custom assertions ## QUnit.push( actual === expected, actual, expected, message ); # Config API ## JSON.stringify(QUnit.config) lists all configurable properties displayed on the toolbar ## QUnit.config.urlConfig.pop() removes each configurable property from the toolbar ## QUnit.init() is used for lazy load initialization of QUnit ## QUnit.config.reorder = false is used for showing tests in source order, not fail order # Logging API ## QUnit.log = function log(details){console.log("Hi"+{"Actual":details.actual, "Expected":details.expected, "Source":details.source});} # HTML fixtures ## use #qunit-fixture to match the DOM tree your site actually contains #DOM/JSON Data Dump ## QUnit.jsDump.parse() serializes DOM and JSON

TRANSITION from console.log and global variables

Traditional Development # Comments # console.log # window.location # Date.now()
TDD # Behavior description # spy # stub # mock Date

TEST FIRST DEVELOPMENT

module('foo', bar);

function bar() { /* Move to before or setup step / var glob = ""; var app = init(public_method); app.method = function(){ / move to spy */ console.log(app.public_method());

  return app.public_method();
}; 

 /* move to QUnit or Jasmine assert syntax equivalent */
console.assert(app.method, true, "foo");

/* Move to after or teardown step */
app.on("destroy", function(){ var glob = app = undefined; })
}

TEST STRUCTURE

Jasmine
describe('name',cb)

function pre() { myglobalvar = 'https://us.etrade.com'; myglobalfn = Date(); myglobalnamespace = mvstar;

mvstar.init();
spyOn(mvstar, "public method"); }

function post() { var myglobalvar = myglobalnamespace = myglobalfn = app = undefined; }

function cb() { beforeEach(pre); it('behavior', function() { app.method(); expect(mvstar.init).toBeDefined(); expect(mvstar.public_method).toHaveBeenCalled(); } afterEach(post); }

QUnit
module('name',cb)

function pre() { var glob = "" var app = init(); }

function post() { var glob = app = undefined; }

function cb() { setup(pre); test('behavior', function() { var foo = app.method(); equal(foo, true); } teardown(post); }

DEPENDENCY INJECTION IN TESTS VS CODE

  • load the module
  • inject a function pointer
  • inject the controller/service and its dependencies into the function literal
  • initialize the public properties
  • call the public methods
  • assert the boolean state of the return values (based on data type, equality, pattern, or truthiness)
  • assert attempts to call methods of dependencies using spies
  • replace session or network based data using mocks
  • rerun using alternate public properties to access else branches
Angular Mock
  myAppDev = angular.module('myAppDev', ['ngMockE2E']);
  test = angular.injector(['myAppDev']).get('$test');
  $httpBackend = angular.injector(['ngMock']).get('$httpBackend');
Angular Module
  myAppDev = angular.module('myAppDev');
  test = myAppDev.constant('test', ['$http',function($http){}]);
Angular Mock
   module('trading');
    module('et.shared.neoServices');
    inject(snapshotServiceTest);

function snapshotServiceTest(snapshotService) { var result = snapshotService;
expect(result).toBeDefined(); expect(result.chartQuotes).toBeDefined(); expect(result.chartURL).toBeDefined(); expect(result.indexQuote).toBeDefined(); expect(result.symbolQuote).toBeDefined(); }

Angular Module
'use strict';

function snapshotService($q, $http, neoresource, $filter, chartFilter) { var api = { chartQuotes: chartQuotes, indexQuote: indexQuote, symbolQuote: symbolQuote, chartURL: chartURL }; return api; }

angular.module('trading', ['et.shared.neoServices']) /* app.js */ angular.module('trading').factory('snapshotService', snapshotService);

MODULAR TESTS

Jasmine
/*
describe() maps the plain English behavior to the test code

it() defines the user behavior and the implementation

beforeEach() adds dependencies into the global scope before the test

spyOn() acts as an interceptor to override method calls

toHaveBeenCalled() asserts whether the methods have executed

toHaveBeenCalledWith() asserts whether the method signature is correct

afterEach() removes dependencies from the global scope after the test

spyOn also acts as stub to replace host objects angular.module(['ng'], function($provide) { $provide.value('$window', {location: jasmine.createSpy('location') } ) } ) */

describe("when a song is playing, we can toggle between play and pause", function() { beforeEach(function() { player.play(song); }); it("should pause the song", function() { spyOn( player, "pause" ); // define the spy player.togglePlay( song ); expect( player.pause ).toHaveBeenCalled(); expect( player.pause ).toHaveBeenCalledWith( ); }); it("should play the song", function() { spyOn( player, "play" ); // define the spy player.pause(); // just called here to set up our test to play the song next. player.togglePlay( song ); expect( player.play ).toHaveBeenCalled(); expect( player.play ).toHaveBeenCalledWith( song ); });

QUnit
/*
module() groups tests into a namespace 

test() namespaces the test and its implementation

setup() adds dependencies into the global scope before the test

teardown() removes dependencies from the global scope after the test */

module("jQuery#enumerate");

test("chainable", 1, function() { var items = $("#qunit-fixture li"); strictEqual(items.enumerate(), items, "should be chaninable"); });

test("no args passed", 3, function() { var items = $("#qunit-fixture li").enumerate(); equal(items.eq(0).text(), "1. foo", "first item should have index 1"); equal(items.eq(1).text(), "2. bar", "second item should have index 2"); equal(items.eq(2).text(), "3. baz", "third item should have index 3"); });

test("0 passed", 3, function() { var items = $("#qunit-fixture li").enumerate(0); equal(items.eq(0).text(), "0. foo", "first item should have index 0"); equal(items.eq(1).text(), "1. bar", "second item should have index 1"); equal(items.eq(2).text(), "2. baz", "third item should have index 2"); });

AJAX TESTING

Jasmine
/*
waits(time) stops code execution for a specified interval

runs(function) resumes execution at the end of the callback

waitsFor( function, msg, maxTimeOUt ) calls its function repeatedly until it returns true, so beware

expect() defines the comparison which should be true at the end */

//Simulates an async function by waiting until it has been called 50 times. var globalCounter = 0; var pingCounter = 0 function returnAfterWait( ){ pingCounter++; if ( pingCounter == 50 ){ globalCounter++; return true; }
}
describe('This is an async test', function(){ //this test waits 500 ms before testing the results it('should test async with timer', function(){ var counter = 0; runs( function(){ setTimeout( function(){ counter++; }, 500 ); }) waits( 505 ); runs( function(){ expect(counter).toEqual( 1 ); }) }); /* This test waits to continue until returnAfterWait() returns true */ it('should test async with a return', function(){ var counter = 0; waitsFor( function() { return returnAfterWait(); },'this is the async message', 5000 ); runs( function(){ expect(globalCounter).toEqual( 1 ); }) }); });

QUnit
/*
asyncTest() is a syntatic sugar forr Test( fn{stop()...start()} )

start() resumes execution at the end of the callback

expect() defines the number of assertions we should be triggered once start() is called */ asyncTest("async3", function() { expect(1); $.getJSON("resource", function(result) { deepEqual(result, { status: "ok" }); start(); }); });

Flask

# tests.py
import pytest
from flask import Flask
from flask_injector import FlaskInjector
from dependency_injector.wiring import inject
from app import app, Container

@pytest.fixture
def client():
    app.container = Container()
    FlaskInjector(app=app, modules=[app.container])
    with app.test_client() as client:
        yield client

@inject
def test_my_utility_function(client, my_service: MyService):
    response = client.get("/")
    assert response.status_code == 200
    assert my_service.some_method() == "result"

References

[http://ditwebdev1w204m7.etrade.com/psweatte/qunit/qunit_builder.html QUnit Builder (Internal)]

[http://msdn.microsoft.com/en-us/magazine/gg490346.aspx BDD Primer]

[http://www.slideshare.net/tasanakorn/javascript-testdriven-development-tdd-with-qunit TDD with QUnit]

[http://benalman.com/talks/unit-testing-qunit.html Unit Testing with QUnit]

[https://www.adobe.com/devnet/html5/articles/unit-test-javascript-applications-with-jasmine.html Unit test JavaScript applications with Jasmine ]

[http://www.slideshare.net/larsthorup/advanced-jasmine Advanced Jasmine]

[http://stackoverflow.com/q/21766034/1113772 Jasmine with PhantomJS]

[http://www.devmynd.com/blog/2014-1-ember-js-testing-with-jasmine Ember.js Testing with Jasmine]

[https://gist.github.com/rjackson/6269405 Basic Ember.js Test Setup with QUnit]

[http://josephchapman.com/post/jasmine-mocks-and-spies/ Jasmine Mocks and Spies]

[http://pivotallabs.com/testing-javascript-promises/ Testing JavaScript Promises]

[http://www.slideshare.net/emwendelin/test-your-javascript Test your JavaScript]

[http://msdn.microsoft.com/en-us/library/hh404088.aspx Unit Testing Web Applications]

[https://github.com/larrymyers/jasmine-reporters Jasmine Reporters Plugin with JUnitXMLReporter]

[https://github.com/jquery/qunit-reporter-junit QUnit JUnit Reporter Plugin]

[https://github.com/devongovett/qunit-cli QUnit CLI NodeJS Plugin]

[https://github.com/gregjsmith/ng-demo-stack Ng Demo Stack:Angular + Browserify + QUnit + Sinon and Phantom]

[http://pivotallabs.com/jasmine-2-0-add-ons/ Jasmine 2.0 and Add-Ons]

[https://github.com/jquery/jquery-simulate jQuery Simulate]

Jest

References

http://www.oracle.com/us/technologies/java/assertions-139853.html

⚠️ **GitHub.com Fallback** ⚠️