I know I should be Unit Testing, but I don't know how or where to start
source link: https://www.aligneddev.net/blog/2018/getting-started-with-unit-testing/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
I know I should be Unit Testing, but I don’t know how or where to start
I’ve talked to many developers about why Unit Testing (as well as automated integration and acceptance testing) and why I think it should be something that is a natural part of development. I usually get the a few similar responses from those who haven’t adopted this viewpoint.
“I know I should be Unit Testing and that it can be helpful, but …”
- “I don’t have time to figure it out and it’s not built into the quote.”
- “I don’t know how or where to start.”
- “I’ve been successful for a lot of years, why change now?”
I hope to help you get started moving past not knowing how and where to start and make automated testing as normal to you as writing code.
Check out my reorganized version of this article for my presentation with a Github link!
Terms
- Testable code
- Code that has testing seams, SRP (Single Responsible Principle) classes and methods.
- Dependencies injected, example: new EmailSender() “new is glue”, cannot be faked, pass in an IEmailSender into the constructor instead
- Automated Test
- code that tests your code
- a more generic term I use to describe the tests below
- not a manual test done by a human
- Unit Test
- test code that covers a small, isolated unit of code
- slower pieces such as SQL, files, network calls would be Faked to return expected values
- The Art of Unit Testing defines it as “A unit test is a piece of code that invokes a unit of work and checks one specific end result of that unit of work. If the assumptions on the end result turn out to be wrong, the unit test has failed. A unit test’s scope can span as little as a method or as much as multiple classes.” [1, pg 5]
- Integration Test
- “any tests that aren’t fast and consistent and that use one or more real dependencies” [1, pg 7]
- Acceptance/UI Test
Unit Test vs Integration test [4]
My Journey
My first exposure to Unit Testing was in our Software Development class at the University of Minnesota, Morris in 2004. We had A Practical Guide to eXtreme Programming and we committed to paired programming, team roles and Test Driven Development (TDD) in Java with nUnit. I learned a lot about coding and process in that semester and I’m thankful for that experience.
In my first development job after college in 2006, the latest and greatest technology was Microsoft’s WebForms. WebForms was not conducive to unit testing. The code behind and server side events tightly coupled the code and made it hard to write testable code. I also wasn’t surrounded by developers who valued unit testing. During this time, I didn’t see (or realize) the need to write test around my code. We were also creating smaller applications (e-commerce, site content apps) and though we had some quality issues, unit testing didn’t come up as an approach we should take.
In 2008, I first read The Art of Unit Testing by Roy Osherove (thanks to @t3rse for lending it to me). This was eye opening to me. I started applying tests to help myself with MVVM Silverlight applications to keep focused and on the right track.
I talked about testing often, but didn’t really apply this until 2013. I was on a new ASP.Net MVC with client side heavy project. The team decided to test the Controllers in C# as much as possible and Javascript using Jasmine. There was a lot of work to figure out how to fake out MVC results and Entity Framework, but it felt rewarding to me. We did not have a build system, so these tests quickly fell out of use when we brought on a contractor. A few months after I left, I was told that one of the team had just spent a few days fixing tests that others had broken and not been running. Lesson learned: tests quickly become large technical debt if they aren’t embraced by the whole team and not forced by a build system.
Later in 2013, I joined a team at a company that decided to invest heavily in automated testing. I was brought in to write automated UI tests with C# and Selenium. We also read Continuous Delivery. Eventually we learned that UI tests are brittle (timing issues with the DOM are the worst) and take a lot of work to maintain. It also started making sense to have developer write the UI tests along with their work. I was then able to move into the regular development cycle. We were using KnockoutJs which enabled the MVVM pattern in our TypeScript client code. Jasmine testing also was decided on by the team and the number of tests slowly grew (now it’s normal and expected). Near the end of 2017, we have 4754 tests and counting. Our team is using Git and Pull Requests to help with code reviews and ensuring quality. Once a PR (requiring fast tests to pass) is complete, it is merged into master and the builds do their work. Each PR is a release candidate that could be released if all tests pass. We’re able to move quite quickly while limiting the amount of manual testing that is needed.
I was moved to work with a different company in the summer of 2018. The(building on top of 30 years of systems) project that is now several years old without tests, lacking separation of concerns in the code and loads of regression issues has been a challenge. - I had a lot of FDD (Fear Driven Development) after changing some things and breaking other things - The company wanted to have automated tests, but deadlines drove them not to do them - Regression bugs are most of the work we’ve been doing in the last months. We often hear, “this used to work” or “we fixed this a few months ago” - A unit testing committee was formed to get tests going and educate. The Art of Unit Testing book club was done together and we are starting to hear stories how the tests stopped a regression issue. - in the summer of 2019, we only have 12% coverage (in our part of the system), but that’s increasing and new code is mostly getting covered - people are mentioning it more in Code reviews and adding them before getting asked to more and more
Some recent Tweets:
It's never to late to automate #unittesting
— Kevin Logan (@alignedDev) June 12, 2019
I added a Automated Testing section to my old article https://t.co/lLfwRQVUE6 with a link to @weeklydevtips
— Kevin Logan (@alignedDev) May 13, 2019
Lessons Learned
- A build that enforces tests pass are essential for success. Otherwise the tests quickly become obsolete and technical debt.
- It will take time to change an individual’s and team’s work flow to write tests. It may require a management level decision or the team may come to a mutual agreement after seeing the benefits.
- You may have to be the agent of change (see the Art of Unit Testing chapter 9 for good ideas here). Be persistent, but not condenscending or over bearing.
- You need team buy in. Writing tests on your own will help you and give you opportunity to improve and show the benefits to others.
- Automated tests at many levels are required for Continuous Delivery and DevOps approaches. Without them, manual testing and the feedback loop take way to long on a complex system.
- UI Tests are brittle, but very helpful
Follow the Testing Pyramid. Unit tests are the foundation and the fastest feedback for developers. Then integration and finally UI Automation tests. Flipping that over (the ice cream anti-pattern) will cause a lot of difficulties. You’ll find yourself trying to reduce the UI tests after the test fails on a timing issue for the 10th time.
Manual exploration testing is still very important. QA minded engineers know how to break things. Talk to them (and business people) before starting to code to help define specifications with examples [3]
Why Write Tests
There are many reasons, discussions, books and articles. I’ll highlight a few that I think are important.
- Fast feedback
- Instant with fast unit tests!
- learn faster
- small or big steps with the TDD approach
- stop manually clicking buttons and hitting a break point. That’s a manual form of automated testing. Tip 61 from The Pragmatic Programmer [2] says “Don’t use Manual Procedures” [2, Tips section at the back]
- Manage risk
- little to no regression bugs in a well tested system
- Reduce fear of changing code
- safe to refactor
- Better modular code
- Tips 34 “Code That’s Easy to Test”, 62, 63, 64,65,66 from The Pragmatic Programmer all mention testing [2, Tips section at the back]
- think before coding
Senior developers’ experience “If you’ve never tried test driven dev, you’re missing out. Even after years, watching a test go from red to green is immensely satisfying.” Cory House on Twitter.
Can’t do CD or DevOps practices without it.
Where to start
As we noted above, the hardest part of changing processes and approach to programming is knowing where to start.
- Read The Art of Unit Testing by yourself or better yet with your team.
- Consider reading Test Driven Development: By Example By Kent Beck [6], but don’t wait to start until after reading. This book walks step by step of using TDD. NOTE: You don’t have to do TDD, but a lot of people find it helpful.
- Watch a Pluralsight or MVA or other videos 1.MVA TDD 1.Pluralsight - Basic Unit Testing for C# Devs
- Watch and learn from others who are already using Unit Testing
There are many possible places:
- new code - start a new practice app, do a kata 2, or start with new code in your application.
- reported bug - write a test and never have to fix it again
- simple part of the system
- highly used and core pieces of the system
Word of caution: Expect to spend a lot of time adding in your first tests in existing code that wasn’t written with testing in mind. It takes refactoring and a lot of work to add in the proper testing seams for faking. It also takes practice and time to write good tests.
The best way to learn something is to start doing it and practice.
I’m working on a Part 2 which will have examples in C#, Asp.Net MVC Core and with TypeScript code. Hopefully, I’ll have this up early 2018.
Hints
Kent Beck in TDD [6] makes a list of things that need to be done and works through the red, green, refactor loop while crossing things off the list. I found this to be a great idea (it works well for debugging tough issues too).
Challenges
- It’s an “art”, so I can’t tell you exactly how to do it.
- It takes a lot of work to build up a suite of good quality tests.
What to look for in a code review?
I took an informal survey and here are some good things to look for in unit tests.
- That they exist, that they are testing reasonable contracts and not internal details, and that the run automatically in CI.
- That integration tests are testing a common path unless the ticket is for fixing a rather important bug.
- That unit tests are readable at the individual test level.
- Does the unit test(s) provide value for the work being checked in?
- Does the unit test(s) address the newly added logic with multiple flows
- Good use of Seems – how do we handle dependencies in the code?
- Cleanliness of tests – how hard will the tests be to maintain? Is there good use of factory functions? Is there anything that would cause dependencies between tests?
- Use of mocking frameworks – Is the use of a mocking framework justified? Could the tests be simplified by “Extract and Override”.
- Tests actually test something – that is, they are not assertions about the current state of the codebase that will break as soon as a change is made, or never break in a meaningful way.
- No inter-test dependencies – I usually only start looking for this with tests that have shared setup code.
- Ask the question “When will this break?” And the answer is “If you choose to change the method called by the controller” and pretty much no other time - it’s not really going to save you from anything you didn’t intentionally do.
Resources
- Do yourself a favor and get The Art of Unit Testing book [1]. If you’re looking to get started or hone skills, read this book!
- Start with the first chapters and if you get bogged down in the middle jump to Chapter 9 with help on becoming an agent of change
- Chapter 9 also has a section named “How much time will unit testing add to the current process?”
- “Properties of a good unit test” [1 pg 6]
- My old 2014 article about testing an MVC application
- MSTest V2 is now very similar to nUnit for C# testing. I’ve been using this version for a while now.
- What is software unit testing and why is it important? on Quora
- The DevOps Handbook discusses automated testing in Chapter 10 “Enable Fast and Reliable Automated Testing”. There’s a case study of Google moving towards automated testing. Manual testing is “totally unscalable” [5 pg 123] for continuous deployment and DevOps practices.
DevOps Journey from Microsoft. “Automation is key — Automation should be considered and pursued across all areas of the software lifecycle, especially if the organization is planning on making changes to roles and accountabilities. Manual efforts, especially in the spaces of testing, environment creation, and release management, can significantly delay delivering value to customers.”
Art of Unit Testing book – Roy Osherove - start here
- We’ve used this as a book study for 6 weeks 3 times at Omnitech in the last 8 years.
- https://courses.osherove.com/courses
The Phoenix Project book – DevOps story by Gene Kim
TDD Video - https://twitter.com/unclebobmartin/status/1032405401009041409
Test Driven Development book – Kent Beck
Accelerate DevOps book – Nicole Forsgren, Jez Humble, Gene Kim
Microsoft Virtual Academy – TDD - https://mva.microsoft.com/en-us/training-courses/testdriven-development-16458?l=iCWHq6vXC_2706218965
The bowling Kata section is eye opening
Clean Code book - Robert Martin
Specification By Example book – Gojko Adzic
HttpClient
Add a TODO and don’t start “shaving a yak“
-
- a new way (for me) to think through writing tests
Architecting Modern Web Apps with ASP.Net Core 2 - Section 9
.Net Core Unit Test and Code Coverage with Visual Studio Code
Citations
[1] Osherove, Roy. The Art of Unit Testing Second Edition. Manning 2014
[2] Andrew Hunt and David Thomas. The Pragmatic Programmer. Addison-Wesley 2000
[3] Gojko Adzic. Specification by Example: How Successful Teams Deliver the Right Software. Manning Publications June 6, 2011
[4] Downloaded from https://media.giphy.com/media/l0MYSpvx4pnsoMNz2/giphy.gif, seen on https://hup.hu/node/149706 October 12, 2017
[5] Gene Kim, Jez Humble, Patrick Debois and John Willis. The DevOps Handbook IT Revolution 2017
[6] Kent Beck, Test Driven Development: By Example, Addison-Wesley Professional; 1 edition (November 18, 2002) * https://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530
A few more links
“A National Institute of Standards and Technology study found that it costs twice as much to make minor enhancements to a system than it cost to build the system in the first place.” “Why is it so expensive to add features to existing software? In a nutshell, it’s because we don’t value writing changeable code, or we think that writing changeable code will take much longer to write. “
Why do programmers fail to write good unit tests
Why Learning TDD is hard and what to do
I’m using this material for South Dakota Code Camp 2018. The link will only work until the next code camp ;-).
A lot of people have opinions on Stack Overflow
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK