Software Architecture in Golang: Testability

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello my name is mario welcome to another software architecture and go video in today's episode i'm going to be covering testability why testing is really important and i will show you a few different examples using go there are two books i like to mention when discussing software testability one of them will be a software architecture in practice published in 2012 that defines software testability as the is with which software can be made to demonstrate its faults through typically execute base testing the other one i like to mention with together with this one will be one that includes this concept of automation pyramid that is succeeding with agile published in 2012 by mike kahn and and this is important i want to bring it up because the way this pyramid is defined will be a guideline for what we're going to be doing when building tests the way mike cohen likes to mention that in his book is that there is this layer of unit testing service testing and ui testing and one thing that is not included in the book but i like to mention is the concept of manual testing now for our use case which is building backing apis because we are building micro services specifically for the back end and i'm not including any user interface the layer for user interface is not going to be mentioned in that specifically but rather the api that we are publishing uh making available to our customers for example http rest api for example or maybe using grpc or something along those lines similar with the service layer we are talking about the integration which which means when we are in interacting with data stores for example so when we're talking to a database when we're talking like um a memcached or postgres of my sequel or whatever the case may be now typically when we are building a system and then building a not only microservice but whatever program that we're trying to build one of the things that is usually sacrifice is testing and this is because when we're trying to build something we either the way that we're given the requirements and the constraints our customers or our stakeholders want to have something fast something good and something cheap but all of this is competing because you can have something fast and good and also the same time being cheap so most of the times what is sacrifice is testing and testing is one of those things that if you're trying to ignore eventually it will come come back and hurt you in the long term now there is this um research this paper that was published by the national institute of standards and technology in 2002 that is called the economic impacts of inadequate infrastructure for software testing and i want to show this diagram because it's relative to how much cost relative to money time effort or or human power or whatever the case may be when we are finding defects in different phases of the software development process so relative cost to repair defects now i want you to pay attention to planning coding integration customer feedback and post release and this is again relative to cost money or you know human resources whatever the case may be so when you're planning you have a cost of one you're planning you're building your detecting defects you're fixing it right away if you're coding it will relative to five if you're integrating when you're actually deploying something but nobody's actually using it you're deploying it to a live environment well it will be 10x if there is a customer feedback it will be a 15x because now somebody is using it and and they detect the errors that you should have detected in the first place and the big one will be the post release which is 30 x times what this means in practice is that if we don't have tests in place when we are building a project a software system is going to be much more cost and it will take cause it will cost us more much more whatever money human resources whatever it is maybe if we do this after we deploy the system so this is something to keep in mind and i i want to share if you're having trouble sharing or making your case to your manager or your stakeholder and they're telling you hey don't add any tests don't worry about it delegate it to somebody else share this graph with them and hopefully they can change their mind let me show you the actual examples using go for the different examples that the pyramid that i was showing you in the beginning and how this works in real life the examples i want to show you will be linked in the description of this video so feel free to check that out and what i'm going to be giving you is a walkthrough to the existing implementation to you have an idea of what i'm we're what we're talking when we're referring to the unit test if we go back to the pyramid diagram that i was showing you it was covered in unit test then it's a service or integration and there are some ui api tests that we are not going to be covering but i will be leaving you an example a link to how to test those because typically when you have your testing suite that you are going to be implementing what you should be focusing on most of the time will be the things that are easier to test and they give you better feedback and are easier to implement in the context of how much you have to do when you are running those tests so when you have unit tests you're testing the domain your domain and then also the integrations that happen on the above layer on the layer above it that happen to be accessing databases or maybe accessing external apis and you can somehow mock and stuff all of those things i don't want to go through manually implementing all those tests i already did that in a different video i will again i will be leaving the link to those videos as well typically what's happening when you're implementing unit tests and the way you like to think about it is that you don't have any external dependencies order that you cannot mock directly using either you know your typical standard library functions or methods or types or maybe using a third-party package that generates those types for you now if i use a time like dates that i have right here what we're going to be doing is implementing a test for validate and obviously for all the functions that i have i want to run the tests first so you can see that most of these things are covered i haven't really covered all my tests in this specific project but if you notice what green indicates when you're running code coverage that again i cover in a different video regarding maintainability it's important to also keep that track of all those things that you're adding and removing when you're making changes to your service is one of the you know like a fitness function that again i cover in a different video i will put the link in the description so if i jump and look at the priority all right the validate for dates i'm actually going through all the different use cases that i implement for that are required for this type now one important thing that i want to show you is the structure that i'm using and this is the recommended way the idiomatic way of implementing tests in go which refers to using what they call as a test table driven a writer table driven testing which it means is that you're creating a slice that happens to include different tests with their input and their output and and the some sort of like indicator of what's the name of test and then you use invoke again depending if you're testing like an exported api or an import or our own exported api you do those things in a different way what i'm trying to do here is test if there is an error when validate is returned now i have different use cases that indicate this is an error all right this is not an error and and there are different indications this is an error and and finally the one that truly returns the error will be when i'm trying to use start as the one that is higher than the do so it means that i cannot indicate in the context of the date type that i have right here i cannot define it as it is starting before it ends or rather it starts after it ends so it's kind of like weird that that's not valid and typically the structure that i like to use will be you know again all of this is the recommended idiomatic way of defining tests in go so you run your tests using again define a test suite or test cases and then you run a suite and you run it as a suite in a range loop and then for each test you run those in parallel with a core routine that is applicable to the testing package and then you use execute whatever you have to execute this will be a concrete example of a unit test that happens doesn't have doesn't have anything been a stub or mock at the moment now if you go and jump into the next one which will be for example when we are testing the service or i don't have a test for service when we're testing something like uh the postgres package i have a task let me close this too i have a task type that is used for accessing the database and adding records so for example we have a create and what create does if you notice is just literally doing an insert into the database nothing else so what we're trying to do here is that we're trying to test the create and in my experience one of the trickiest part about doing integration testing with go and in general basically is defining the pre-requirements that you have to have and it gets tricky because most of the times again it depends and you can do it if you spend some effort when you're trying to define something similar to what we did with a with the previous test with the to-do test where we had a task a table driven test it gets more difficult because when we are doing integration tests we're literally accessing a database for example or maybe a data store whatever the case may be and those have a state and and depending on how you configure each one of your tests you may need to do certain things in a certain way to allow the table driven test to work typically what i suggest doing is create those tests one by one and still run them in parallel but not using the table driven test idiomatic way of doing things i know it's one of those tradeoffs that you need to make now what about the other use case when you are actually trying to test the api the public api that you have for example that would be the rest api that i have right here and in that case i have the task endpoint that i'm doing you know i'm creating and updating i'm deleting those kind of actions that come in http and i'm defining a few different routes and doing those kind of you know actions via the handlers what i typically do is if i go for example delete that one i can actually use what i defined before in my domain type my domain package under the internal which i was showing you before is that i can do still do something like the table driven tests because these ones because of the way i structure my project i can mock those dependencies via dependency injection using stubs and spies and those kind of things for this specific example that i'm using for the rest api i'm actually using a tool called counterfeiter then again i will be leaving the link in the description and it's just for generating those kind of things on your behalf so you don't have to do them manually you can always use do you do those manually and what not and again this follows the same structure and and what not again i'm trying to go as fast again this is not a tutorial but i it should give you an idea and and what the things that you will be needing when trying to test different things now if i go and show you the actual code coverage in the html page you will notice that some of the things are actually already covered by the implementation that i have right here and you can refer to the service that i use for specifically for code coverage which is called codecov that shows you the different code coverage and then different things and again discover part of the maintainability uh discussion that i i mentioned you know a few weeks ago and whatnot now let's jump into the conclusion and i will show you i will talk to you in a few seconds so this is the stability in go not covering all the different aspects considered to or related to testing i will be doing that in future episodes i just want to give you a quick walkthrough of what testability means and how important that is when we're talking about money and resources and really the long term life of our project that we're going to be implementing and building now hope all of this makes sense any comments any questions let me know i will be focusing and diving more into testing concrete examples about mocking and stubbing and using all the previous package that i mentioned and i will be revisiting those so you have a better idea how to use all of this together thank you for watching and we'll talk to you next time take care
Info
Channel: Mario Carrion
Views: 533
Rating: undefined out of 5
Keywords: golang, golang testability, golang testing, golang software architecture testability, golang software architecture testing, golang test, golang counterfeiter, golang table driven tests
Id: tPpJkNrLcnk
Channel Id: undefined
Length: 14min 5sec (845 seconds)
Published: Fri Nov 12 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.