After spending a lot more time testing apps, I see this post as being a naive attempt at simplifying a topic that is a lot more nuanced. The ideas exposed here may still be useful for beginners but may be impractical in some cases. EDIT: JavaScript “Code without tests is broken by design” — Jacob Kaplan-Moss Testing is not optional. It is not a time-consuming task that you can shave off to gain productivity. As a developer, it is your responsibility to deliver quality software and that quality cannot be guaranteed without automated tests. That being said, there are situations where testing is not trivial unless you have a few tricks up your sleeve. These hard-to-test pieces of code usually involve side effects or global variables that take different values in different environments. In this post, I will show some of these problems in code examples and propose a coding pattern to alleviate a lot of that testing pain in JavaScript. Code structure Imagine you are writing a component (you don’t need to know React Native to understand any of this). Your component needs a function that, given a width in px, calculates the corresponding percentage of screen real estate. I like to keep most of my logic outside of my React components, so let’s create an independent JavaScript module for that: React Native // Scaling.jsimport { Dimensions } from 'react-native'; export const widthInPxToPercentage = (widthInPx) => {const screenWidth = Dimensions.get('window').width;return (widthInPx * 100) / screenWidth;}; The function works, but it’s hard to test because it is . A pure function is a function that always returns the same output for the same input. Conversely, an impure function is one that may have side effects or depends on conditions from the outside to produce a value. In order to make our function pure, we can refactor it to take the screen width as an argument. This technique is known as (DI). Don’t get scared by the fancy term, though. We won’t be using dependency injectors or any sophisticated dependency management mechanism. Our refactored code would look like this: impure dependency injection // Scaling.jsimport { Dimensions } from 'react-native'; export const widthInPxToPercentage = (screenWidth, widthInPx) => (widthInPx * 100) / screenWidth; This is much more testable! However, with this approach, all clients of our module will need to pass the screen width in. What I like to do in these cases is separate the implementation from the API using two functions: // Scaling.jsimport { Dimensions } from 'react-native'; export const widthInPxToPercentageImplementation =(screenWidth, widthInPx) => (widthInPx * 100) / screenWidth;export const widthInPxToPercentage =widthInPx => widthInPxToPercentageImplementation(Dimensions.get('window').width, widthInPx); The implementation function is a pure function that can easily be tested and is not visible outside the module (more on that later, don’t worry about that extra ). In this example, it is very simple but in the real world, you’ll often find yourself writing these as higher order functions since some dependencies will turn out to be functions. export The entry point is a function exposed to the outside-world that invokes the implementation passing the dependencies in, so that clients don’t need to worry about them. These are typically one-liners that you don’t need to unit test (although your integration tests will most likely cover them). Now, let’s add our test: // Scaling.spec.jsimport { widthInPxToPercentageImplementation } from './Scaling'; test('test 10px is 10% of 100px wide screen', () => {// Givenconst screenWidth = 100;const widthToConvert = 10; // When const widthInPct = widthInPxToPercentageImplementation(screenWidth, widthToConvert); // Then expect(widthInPct).toEqual(10.0); }); You have now made your code testable by using DI! Directory structure and visibility Some people put their tests in a directory in the project's root. I don't like that approach because it's not portable: If you copy code to another project, you need to grab the implementation and the tests from completely separate places. Instead, what I like to do is put my tests in the same folder as my code (notice the relative import in the snippet). This makes your test code more portable and encourages developers on your team to treat tests as an integral part of the development process. __tests__ Also, you may notice that in I exported both the implementation function and the entry point. The entry point needs to be visible to the outside world, but the implementation doesn't. However, I have no means of using the implementation function inside tests unless I export them, so I have to export both. In order to better organize the visibility of the module, I use an file alongside the implementation and test files. In this file you can specify the API you want to expose to the outside world by using an statement. Our file should look like this: Scaling.js index.js export ... from index.js export { widthInPxToPercentage } from './Scaling'; This approach has two drawbacks that aren’t deal-breakers but you should be aware of: It creates a little bit of duplication and it doesn’t prevent people from accessing the module from the outside world. The duplication is not terrible, although I must admit it does feel a little like maintaining files. The visibility shouldn't be a problem if your team is aware of this convention and you use references to the directory instead of the implementation file when you import the module. That is, import instead of : When you import a folder with an file, JavaScript will import the file impliscitly. .h 'src/Scaling' src/Scaling/Scaling index.js index.js PRO Tip: If you're a Vim user you can run By now, your module is complete and looks like this: src/Scaling/├── Scaling.js└── Scaling.spec.js You now have a pattern to structure your code in a testable manner while encouraging others to jump on board with the same practice. This is by no means a one-size-fits-all solution and your team might need custom conventions, but the important thing is that they exist. What do you think about this pattern? Do you know of a better way to solve this problem? Let me know in the comments or on Twitter . @bug_factory is how hackers start their afternoons. We’re a part of the family. We are now and happy to opportunities. Hacker Noon @AMI accepting submissions discuss advertising & sponsorship To learn more, , , or simply, read our about page like/message us on Facebook tweet/DM @HackerNoon. If you enjoyed this story, we recommend reading our and . Until next time, don’t take the realities of the world for granted! latest tech stories trending tech stories