- Quality and reliability
- An introduction to the "reliability" and "quality" concepts
- Unit / Integration / Functional testing
- Definitions
- Comparison
- TDD
- Testing frameworks for JavaScript
- Debugging
- Debugging tools available for JavaScript
- Global console object
- Node.js console
- debugger statement
- node.js debugger
- Browser's developer tools
- IDE interaction with a browser to debug
- Debugging tools available for JavaScript
- Transpilers
- Babel
- Task runners, bundlers, build systems
- Webpack
- Grunt
- Gulp
- Brunch
- Yeoman
- RollUp
Even though both aspects a intimately related, they're many differences between them. We can think about them in the following terms:
- Quality
- Closest to the code
- Testability
- Readability
- Scalability
- Reusability
- Functional correctness
- Robustness
- "code" defects
- Peer reviews
- unit tests
- Code coverage
- Reliability
- Closest to the execution in a host/environment for a given time
- Stress test
- Load test
- Performance
- Regression test
- "failure" intensity, probability and statistics
- End to end test
- Integration test
- Faults per thousand lines of code in x time
In the software industry, there's a big overlap between quality and reliability, and the better the quality assurances processes applied to the code production, the more reliable the software tends to be.
The bibliography is huge and there are many definitions, sometimes you'll find yourself asking the client "what does quality mean to you" to be able to sketch out a plan and avoid investing efforts in the "wrong" place.
My general approach is that "the quality is owned by the team", every engineer MUST take the necessary measures to warrant the written code and propose corrections if brittle code has been detected. One of the most important measures is to recognize the fact that you WILL introduce defects in the code you write, no matter how much of an expert you are—eventually you'll break something. So don't trust yourself excessively, ask around for opinions, write tests, make it readable instead of "smart" and try to be a better engineer every single day.
Here is some reading to start.
- Software quality
- Software reliability testing
- Reliability engineering in software
- What Is Code Quality? And How to Improve It - by Richard Bellairs
- Software Reliability
- CISQ Code quality Standards
Usually the metaphor of a Pyramid is used to describe the impact of the different testing techniques and how speed, ROI, cost and other aspects are related to them. There are several "Pyramids" with some variations, but usually it starts with unit testing on the base of the pyramid, followed by integration and ending with functional testing, where the base provides the biggest benefits and the rest is built on top of that. (here an interesting article with a variation of this. The practical test Pyramid by Ham Vocke)
I've found this incredibly clear table for the first two types to show you the characteristics of both techniques on the "Software testing class" website.
Unit Testing | Integration Testing |
Unit testing is a type of testing to check if the small piece of code is doing what it is suppose to do. | Integration testing is a type of testing to check if different pieces of the modules are working together. |
Unit testing checks a single component of an application. | The behavior of integration modules is considered in the Integration testing. |
The scope of unit testing is narrow, it covers the "unit" or small piece of code under test. Therefore while writing a unit test shorter code is used that target just a single class. | The scope of integration testing is wide, it covers the whole application under test and it requires much more effort to put together. |
Unit tests should have no dependencies on code outside the unit being tested. | Integration testing is dependent on other outside systems like databases, hardware allocated for them etc. |
This is first type of testing is to be carried out in Software testing life cycle and generally executed by the developer. | This type of testing is carried out after unit testing and before System testing and executed by the testing team. |
Unit testing is not further sub divided into different types. | Integration testing is further divided into different types as follows: Top-down Integration, Bottom-Up Integration and so on. |
Unit testing starts with the module specification. | Integration testing starts with the interface specification. |
The intricacies of the code are given visibility via unit testing. | The integration structure is given visibility via Integration testing. |
Unit testing mainly focuses on testing the functionality of individual units and does not uncover the issues that arise when different modules are interacting with each other. | Integration testing aims to discover the issues that arise when different modules are interacting with each other to build the overall system. |
The goal of unit testing is to test the each unit separately and ensure that each unit is working as expected. | The goal of Integration testing is to test the combined modules together and ensure that every combined module is working as expected. |
Unit testing comes under White box testing type. | Integration testing comes under both Black box and White box type of testing. |
You can think of it in these terms: both features (door and lock) work perfectly as separated units, but the integration fails.
Testing is so important that a particular development process relies on writing the test first and then writing the code to pass them called Test Drive Development! Of course it might sound crazy as many of the Extreme programming related techniques do, but indulge me and think about this:
Given that you have detailed specifications about how your software/feature should work, what if you first think about how the feature should be tested to make it "testable" and "reliable", then you write the abstract tests it's supposed to accomplish, as a contract, and only then start thinking about the actual code for the feature and finally write it. ... Those steps forced you to think before coding, and especially made you concentrate on how to make your code more testable first instead of writing it and having to iterate on refactoring sessions because it is not testable and maintainable enough.
The market provides innumerable resources for testing your JavaScript apps, they can be suitable for unit testing, integration testing, automated testing, for UI/E2E, etc. Each one has its pros and cons and some are designed for specific libraries like QUnit was for jQuery and some are more robust and generic like Jest but most of them evolved to cover more techniques or died along the way.
Here is a list of unit testing frameworks in Wikipedia
So you think that testing your code will be enough huh? LOL not even close, even when you enter a green field (as opposed to legacy code) you'll end up having to deal with "damnit, where the heck is the error?!!!" Some can be detected with the introduction of more accurate tests, and some will escape from every testing attempt leaving you with the happy task of hunting them with creativity, but don't despair, there are several tools to assist you.
Debugging is the process of finding and resolving defects or problems within a computer program that prevent correct operation of computer software or a system.
Debugging tactics can involve interactive debugging, control flow analysis, unit testing, integration testing, log file analysis, monitoring at the application or system level, memory dumps, and profiling.
Source: Wikipedia
Get familiar with the tools available, use them, learn them as you learn how to use your IDE, they'll save you a lot of time.
One of the most used, misused, underused tools is the globally available console
object in your browser. It has several methods (but the engineers insist on using just the console.log
)
Similar to the console
global object provided by Web Browsers but not quite the same.
The debugger statement invokes any available debugging functionality, such as setting a breakpoint. If no debugging functionality is available, this statement has no effect.
An out-of-process debugging utility accessible via a V8 Inspector and built-in debugging client.
Every modern browser will provide you with a battery of tools to inspect and debug your web applications. Network traffic, memory usage, performance, code debugging and many more tools will be available for you to understand how your app behaves on that specific browser.
Some modern IDEs provide you with extensions to be able to use an external browser debugger for your code without leaving your IDE or the other way around, testing an app running in your browser using the IDE debugger.
e.g. Chrome Debugging for VS Code
We saw during this walk that the features defined by ECMAScript might not be implemented in all JavasScript engines. How do we write our code in e.g. ECMA2019 and make sure it'll run on Edge? Transpiling it.
What's a transpiler? essentially a program that takes source code as input and returns source code to match a target system, e.g ES2019 to ES5 or TypeScript to ES2015. This technique lets you write your code in one consistent way and choose how to create an output for a specific target without taking care of many sources.
One of the most used transpilers for JavaScript is Babel
Here you can see how a simple generator example taken from MDN is transpiled by Babel
Original:
function* generator(i){
yield i;
yield* anotherGenerator(i);
yield i + 10;
}
Transpiled:
"use strict";
var _marked =
/*#__PURE__*/
regeneratorRuntime.mark(generator);
function generator(i) {
return regeneratorRuntime.wrap(function generator$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return i;
case 2:
return _context.delegateYield(anotherGenerator(i), "t0", 3);
case 3:
_context.next = 5;
return i + 10;
case 5:
case "end":
return _context.stop();
}
}
}, _marked);
}
You can try it out here.
Well, we went through testing, to testing frameworks to transpilers but how in the world do I make them work together?
JavaScript became a huge ecosystem with many tools and techniques for delivering the code like testing, minification, bundling, linting. Here below I'll list some; each of them provide different features which might be broader (like webpack) or more dedicated to a specific task (like grunt)
Go back to DAY 10 or Go next to DAY 12