{"id":32143127,"url":"https://github.com/dimakura/sspec","last_synced_at":"2025-10-21T07:52:37.844Z","repository":{"id":63908392,"uuid":"107460324","full_name":"dimakura/SSpec","owner":"dimakura","description":"Behavior Driven Development in Swift","archived":false,"fork":false,"pushed_at":"2017-11-07T08:43:51.000Z","size":63,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-10-21T07:52:35.374Z","etag":null,"topics":["bdd","swift","testing"],"latest_commit_sha":null,"homepage":"","language":"Swift","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/dimakura.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-18T20:38:38.000Z","updated_at":"2023-09-09T09:44:02.000Z","dependencies_parsed_at":"2022-11-28T22:53:44.832Z","dependency_job_id":null,"html_url":"https://github.com/dimakura/SSpec","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/dimakura/SSpec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimakura%2FSSpec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimakura%2FSSpec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimakura%2FSSpec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimakura%2FSSpec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dimakura","download_url":"https://codeload.github.com/dimakura/SSpec/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dimakura%2FSSpec/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280225807,"owners_count":26293888,"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","status":"online","status_checked_at":"2025-10-21T02:00:06.614Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["bdd","swift","testing"],"created_at":"2025-10-21T07:52:33.510Z","updated_at":"2025-10-21T07:52:37.839Z","avatar_url":"https://github.com/dimakura.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SSpec\n\nSSpec is a behavior driven development (BDD) framework for Swift and it offers awesome alternative\nto standard XCTest.\n\nIf you worked with behavior driven development (BDD) before, SSpec should be\nalready familiar to you. And it's simple to understand and get started for those\nwho never worked with any BDD frameworks before.\n\n[![Build Status](https://travis-ci.org/dimakura/SSpec.svg?branch=master)](https://travis-ci.org/dimakura/SSpec)\n\n## Installation\n\nAdd SSpec as package dependency in your project's `Package.swift` file:\n\n```swift\n.package(url: \"https://github.com/dimakura/SSpec\", from: \"0.2.3\")\n```\n\nYou should also put it under test target's dependencies:\n\n```swift\n.testTarget(\n  name: \"MyPackageTests\",\n  dependencies: [\n    \"SSpec\",\n    // other dependencies\n  ]),\n```\n\nPackage manager downloads SSpec for you during build:\n\n```sh\nswift build\n```\n\nDo not forget to import SSPec to use it:\n\n```swift\nimport SSpec\n```\n\n## Getting started\n\nYou can easily understand a lot about SSpec looking at this simple example:\n\n```swift\nSSpec.run {                   // 1\n  it(\"2 + 2 = 4\") {           // 2\n    expect(2 + 2).to.eq(4)    // 3\n  }\n}\n\nXCTAssert(SSpec.hasErrors == false)\n```\n\nStandard way to run SSpec is to use `SSpec.run` method as this is done at the\nfirst line of our example. Inside closure for this method we define our test\nexamples.\n\n\nThe first (and only) test example is defined on the second line.\nIt has title (`\"2 + 2 = 4\"`) and one more closure.\n\nInside test example's closure at line three, you can see what this example\nactually tries to test. It makes sure that `2 + 2` is indeed `4`.\n\nYou can place as many examples inside body of `SSpec.run {...}` as needed.\nYou should usually create single `SSpec.run {...}` and define all tests inside.\nSSpec runs all of the examples and checks their correctness.\n\nIf any of the example fails, SSpec will print detailed report of what went\nwrong, so you can easily locate source of the problem.\n\nExample output with default SSpec reporter looks like this:\n\n![Sample Output](https://s1.postimg.org/5rt1xb6zhb/Screen_Shot_2017-11-07_at_12.10.44_PM.png)\n\nTo detect failures programmatically, you can use `SSpec.hasErrors` property,\nwhich is `false` by default, but becomes `true` once there's at least one\nexample failing in your specs.\n\nYou can use this property to report failure back to `XCTest`:\n\n```swift\nXCTAssert(SSpec.hasErrors == false)\n```\n\nThis is not strictly necessary. But when your CI relies on XCTest's failure, it's a handy way to\ndetect errors.\n\n## Grouping tests\n\nTwo global functions `describe` and `context` are helpful for grouping similar\ntests. They are also help to document your code.\n\n```swift\nSSpec.run {\n  describe(\"Person\") {\n    context(\"with high salary\") {\n      let person = Person(salary: .High)\n\n      it(\"is rich\") {\n        expect(person.isRich).to.beTrue\n      }\n    }\n\n    context(\"with low salary\") {\n      let person = Person(salary: .Low)\n\n      it(\"is not rich\") {\n        expect(person.isRich).to.beFalse\n      }\n\n      it(\"is poor\") {\n        expect(person.isPoor).to.beTrue\n      }\n    }\n  }\n}\n```\n\nYou can use `describe` and `context` interchangeably.\nAs a rule programmers use `describe` for grouping examples at high-level,\nsplitting them down to more detailed examples with `context`s.\n\n## Hooks\n\nIf several tests use shared variables or need the same initialization code,\nyou can conveniently use before hook. Before hook runs before each test.\n\nIf you need to cleanup after running each test you can do this using after hook.\n\n```swift\ndescribe(\"Event\") {\n  var event: Event!\n\n  before {\n    // This code runs before each example\n    event = Event(priority: .High, dueDate: Date.tomorrow())\n    event.save()\n  }\n\n  it(\"is urgent\") {\n    expect(event.urgent).to.beTrue\n  }\n\n  it(\"is 1 day away\") {\n    expect(event.daysLeft).to.eq(1)\n  }\n\n  after {\n    // This code runs after each example\n    Database.clean()\n  }\n}\n```\n\nNote that if there are before hooks at different levels, they all get executed\nstarting from top-level. For after hook execution starts with the lowest level.\n\n```swift\ndescribe(\"Level 1\") {\n  before {\n    // this runs first\n  }\n\n  describe(\"Level 2\") {\n    before {\n      // this runs second\n    }\n\n    it(\"Example\") {\n      // this runs after two before hooks\n    }\n\n    after {\n      // this runs first after the \"Example\"\n    }\n  }\n\n  after {\n    // this runs last\n  }\n}\n```\n\n## Matchers\n\n### General matcher\n\nAll values can be tested on presence with `beNil` matcher:\n\n```swift\nit(\"is nil\") {\n  expect(value).to.beNil\n}\n```\n\n### Bool matchers\n\nTo test boolean values, use `beTrue` and `beFalse` matchers:\n\n```swift\nit(\"is true\") {\n  expect(true).to.beTrue\n}\nit(\"is false\") {\n  expect(false).to.beFalse\n}\n````\n\n### Equatable matchers\n\nTODO:\n\n### String matchers\n\nTODO:\n\n### Array matchers\n\nTODO:\n\n## Change matchers\n\nTODO:\n\n## Custom matchers\n\nSwift is strongly typed language.\nSSpec uses types for extending matchers.\n\nSuppose you created custom class `Person`:\n\n```swift\nclass Person {\n  let name: String\n  let salary: Double\n\n  init(_ name: String, _ salary: Double) {\n    self.name = name\n    self.salary = salary\n  }\n\n  var isRich: Bool {\n    return salary \u003e 50000\n  }\n\n  var isPoor: Bool {\n    return !isRich\n  }\n}\n```\n\nand want to have your spec to like this:\n\n```swift\ndescribe(\"Person\") {\n  let jack = Person(\"Jack\", 100000)\n  let jane = Person(\"Jane\", 20000)\n\n  describe(jack.name) {\n    it(\"is rich\") {\n      expect(jack).to.beRich\n    }\n  }\n\n  describe(jane.name) {\n    it(\"is poor\") {\n      expect(jane).to.bePoor\n    }\n  }\n}\n```\n\nAll you need, is to extend `SSExcept\u003cT\u003e` class:\n\n```swift\nextension SSExpect where T == Person {\n  var beRich: Void {\n    // Note that `assert` takes into account negation status.\n    // If you need to know negation status use `isNegate` variable.\n    assert(\n      value!.isRich,                                // `value` is of type `Person?`\n      error: \"Expected \\(value!.name) to be rich\",  // There's also standard `valueStr` variable and\n                                                    // `toString(value:)` function you can use.\n      errorNegate: \"Expected \\(value!.name) to be poor\"\n    )\n  }\n\n  var bePoor: Void {\n    assert(\n      value!.isPoor,\n      error: \"Expected \\(value!.name) to be poor\",\n      errorNegate: \"Expected \\(value!.name) to be rich\"\n    )\n  }\n}\n```\n\n## Configuration\n\n### Reporter\n\nBy default SSpec reports progress with dots.\n\nThere are other options available:\n\n```swift\nSSpec.reporter = .Dot        // default reporter\nSSpec.reporter = .Spec       // most document-like reporter\nSSpec.reporter = .Progress   // progress bar reporter\n```\n\n## Contributing\n\nIf you are interested in contributing to SSpec please [read about it here](./CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdimakura%2Fsspec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdimakura%2Fsspec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdimakura%2Fsspec/lists"}