Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Testing with f#

You're reading from   Testing with f# Deliver high-quality, bug-free applications by testing them with efficient and expressive functional programming

Arrow left icon
Product type Paperback
Published in Feb 2015
Publisher Packt
ISBN-13 9781784391232
Length 286 pages
Edition 1st Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Mikael Lundin Mikael Lundin
Author Profile Icon Mikael Lundin
Mikael Lundin
Arrow right icon
View More author details
Toc

Table of Contents (12) Chapters Close

Preface 1. The Practice of Test Automation FREE CHAPTER 2. Writing Testable Code with Functional Programming 3. Setting Up Your Test Environment 4. Unit Testing 5. Integration Testing 6. Functional Testing 7. The Controversy of Test Automation 8. Testing in an Agile Context 9. Test Smells 10. The Ten Commandments of Test Automation Index

Building trust

What you see as a developer when you look at legacy code is distrust. You can't believe that this code is performing its duty properly. It seems easier to rewrite the whole thing than to make changes to the existing code base.

The most common type of bug comes from side effects the developer didn't anticipate. The risks for these are high when making changes in a code base that the developer doesn't know. Testers have a habit of focusing their testing on the feature that has been changed, without taking into account that no change is done in isolation and each change has the potential to affect any other feature. Most systems today have a big ball of spaghetti behind the screen where everything is connected to everything else.

Once, I was consulting for a client that needed an urgent change in a Windows service. The client was adding online payment to one of their services and wanted to make sure customers were actually paying and not just skipping out on the payment step.

This was verified by a Windows service, querying the payment partner about whether the order had been paid. I was going to add some logic to send out an invoice if the online payment hadn't gone through.

The following is the invoice code:

// get all orders
OrderDatabase.getAllUnpaid() 
|> Seq.map(fun order ->

    // for each order
    let mutable returnOrder = order
    let mutable orderStatus = OrderService.NotSet

    try
        // while status not found
        while orderStatus = NotSet do
            // try get order status
            orderStatus <- OrderService.getOrderStatus order.Number

            // set result depending on order status
            returnOrder <- 
                match orderStatus with
                // paid or overpaid get correct status
                | Paid | OverPaid -> { order with IsPaid = true }
                // unpaid
                | Unpaid | PartlyPaid -> { order with IsPaid = false; SendInvoice = true }
                // unknown status, try again later
                | _ -> returnOrder
    with
        | _ -> printf "Unknown error"

    returnOrder)

// update database with payment status
|> Seq.iter (OrderDatabase.update)

It was implemented and deployed to a test environment in which the logic was verified by a tester and then deployed to production, where it caused €50,000 in lost revenue.

With my failure, I was assuming the OrderService.getOrderStatus parameter really worked, when in reality, it failed four out of five times. The way the service was built, it would just pick up those failed transactions again until it succeeded.

My addition to the code didn't take the side effect into account and started to mark most failed payments with the status of Paid even though they were not.

The code worked fine while debugging, so I assumed it was working. The code also worked fine while testing, so the tester also assumed it was working. Yet, It was still not enough to stop a crucial bug-hit production.

Tip

Downloading the example code

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

Bad code is that which is poorly written and does not follow best practices by swallowing exceptions and letting the program continue to execute in a faulty state. This makes the code harder to change, and the risk becomes higher as a change could introduce new bugs.

Tests written for a program will guarantee that the code has better structure and is easier to change. This is because tests themselves require well-structured code in order to be written. Unit tests drive code to become better designed with higher quality and easier to read and understand.

Integration tests will verify that code written to integrate with external systems is well-written with all the quirks the external system needs, and regression tests will verify that the intended functionality of a system be kept even after a change has been introduced.

Building trust with programmers is all about showing robustness, and this is done by tests. They lengthen the lifetime of a system, as those systems are open to change. They also shine through to the end user, as those systems will not crash or hang when the unexpected occurs.

You have been reading a chapter from
Testing with f#
Published in: Feb 2015
Publisher: Packt
ISBN-13: 9781784391232
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image