{"id":18,"date":"2019-06-17T09:55:43","date_gmt":"2019-06-17T09:55:43","guid":{"rendered":"https:\/\/www.bddtesting.com\/?page_id=18"},"modified":"2019-06-17T10:18:00","modified_gmt":"2019-06-17T10:18:00","slug":"bdd-testing-and-functional-testing","status":"publish","type":"page","link":"https:\/\/www.bddtesting.com\/bdd-testing-and-functional-testing\/","title":{"rendered":"BDD Testing and Functional testing"},"content":{"rendered":"\n

Unit testing is a methodology where units of code are tested in isolation from the rest of the application. A unit test might test a particular function, object, class, or module. Unit tests are great to learn whether or not individual parts of an application work. NASA had better know whether or not a heat shield will work before they launch the rocket into space.<\/p>\n\n\n\n

But unit tests don\u2019t test whether or not units work together when they\u2019re composed to form a whole application. For that, you need integration tests, which can be collaboration tests between two or more units, or full end-to-end functional tests of the whole running application (aka system testing). Eventually, you need to launch the rocket and see what happens when all the parts are put together.<\/p>\n\n\n\n

There are multiple schools of thought when it comes to system testing, including Behavior Driven Development (BDD), and functional testing.<\/p>\n\n\n\n

What is Behavior Driven Development?<\/h3>\n\n\n\n

Behavior Driven Development<\/strong> (BDD) is a branch of Test Driven Development (TDD). BDD uses human-readable descriptions of software user requirements as the basis for software tests. Like Domain Driven Design (DDD), an early step in BDD is the definition of a shared vocabulary between stakeholders, domain experts, and engineers. This process involves the definition of entities, events, and outputs that the users care about, and giving them names that everybody can agree on.<\/p>\n\n\n\n

BDD practitioners then use that vocabulary to create a domain specific language they can use to encode system tests such as User Acceptance Tests (UAT).<\/p>\n\n\n\n

Each test is based on a user story written in the formally specified ubiquitous language based on English. (A ubiquitous language is a vocabulary shared by all stakeholders.)<\/p>\n\n\n\n

A test for a transfer in a cryptocurrency wallet might look like this:<\/p>\n\n\n\n

Story: Transfers change balances<\/code><\/pre>\n\n\n\n
As a wallet userIn order to send moneyI want wallet balances to update<\/code><\/pre>\n\n\n\n
Given that I have $40 in my balanceAnd my friend has $10 is their balanceAnd I transfer $20 to my friendWhen the transfer is completeThen I should have $20 in my balanceAnd my friend should have $30 in their balance.<\/code><\/pre>\n\n\n\n

Notice that this language is focused exclusively on the business value that a customer should get from the software rather than describing the user interface of the software, or how the software should accomplish the goals. This is the kind of language you could use as input for the UX design process. Designing these kinds of user requirements up front can save a lot of rework later in the process by helping the team and customers get on the same page about what product you\u2019re building.<\/p>\n\n\n\n

From this stage, there are two paths you can venture down:<\/p>\n\n\n\n

  1. Give the test a concrete technical meaning by turning the description into a domain specific language (DSL) so that the human-readable description doubles as machine-readable code, (continue on the BDD path) or<\/li>
  2. Translate the user stories into automated tests in a general-purpose language, such as JavaScript, Rust, or Haskell.<\/li><\/ol>\n\n\n\n

    Either way, it\u2019s generally a good idea to treat your tests as black box tests, meaning that the test code should not care about the implementation details of the feature you\u2019re testing. Black box tests are less brittle than white box tests because, unlike white box tests, black box tests won\u2019t be coupled to the implementation details, which are likely to change as requirements get added or adjusted, or code gets refactored.<\/p>\n\n\n\n

    Proponents of BDD use custom tools such as Cucumber<\/a> to create and maintain their custom DSLs.<\/p>\n\n\n\n

    For contrast, proponents of functional tests generally test functionality by simulating user interactions with the interface and comparing the actual output to the expected output. In web software, that typically means using a test framework which interfaces with the web browser to simulate typing, button presses, scrolling, zooming, dragging, etc, and then selecting the output from the view.<\/p>\n\n\n\n

    I typically translate user requirements into functional tests rather than keep up BDD tests, mostly because of the complexity of integrating BDD frameworks with modern applications, and the cost of maintaining custom, English-like DSL whose definitions may end up spanning several systems, and even several implementation languages.<\/p>\n\n\n\n

    I find the layman-readable DSL useful for very high-level specifications as a communications tool between stakeholders, but a typical software system will require orders of magnitude more low-level tests in order to produce adequate code and case coverage to prevent show-stopping bugs from reaching production.<\/p>\n\n\n\n

    In practice, you have to translate \u201cI transfer $20 to my friend\u201d<\/em> into something like:<\/p>\n\n\n\n

    1. Open wallet<\/li>
    2. Click transfer<\/li>
    3. Fill in the amount<\/li>
    4. Fill in the receiver wallet address<\/li>
    5. Click [Send money]<\/code><\/li>
    6. Wait for a confirmation dialog<\/li>
    7. Click \u201cConfirm transaction\u201d<\/li><\/ol>\n\n\n\n

      A layer below that, you\u2019re maintaining state for the \u201ctransfer money\u201d workflow, and you\u2019ll want unit tests that ensure that the correct amount is being transferred to the correct wallet address, and a layer below that, you\u2019ll want to hit the blockchain APIs to ensure that the wallet balances were actually adjusted appropriately (something that the client may not even have a view for).<\/p>\n\n\n\n

      These different testing needs are best served by different layers of tests:<\/p>\n\n\n\n

      1. Unit tests<\/strong> can test that local client state is updated correctly and presented correctly in the client view.<\/li>
      2. Functional tests<\/strong> can test UI interactions and ensure that user requirements are met at the UI layer. This also ensures that UI elements are wired up appropriately.<\/li>
      3. Integration tests<\/strong> can test that API communications happen appropriately and that the user wallet amounts were actually updated correctly on the blockchain.<\/li><\/ol>\n\n\n\n

        I have never met a layman stakeholder who is remotely aware of all of the functional tests verifying even the top-most level UI behavior, let alone one who cares about all of the lower level behaviors. Since laymen are not interested, why pay the cost of maintaining a DSL to translate for them?<\/p>\n\n\n\n

        Regardless of whether or not you practice the full BDD process, it has a lot of great ideas and practices we should not lose sight of. Specifically:<\/p>\n\n\n\n