TL;DR Using your testing framework in everyday routine can drastically decrease amount of repeated actions you perform during debugging, investigation or just playing with your code DRY You know that principle? DRY - . It can be applicable not only for code. Over the years, working side by side with many others developers, i noticed that in most cases we all fail to follow this principle. don't repeat yourself Imagine developing process of some simple API, when initial simple code is already written and you want to test it. The natural intent is to open your favorite browser with autogenerated swagger documentation or postman or any other tool and send request to API. Sometimes you want to put a breakpoint somewhere in the code to explore some third party library behaviour with help of debugger or examine some unclear points. Something similar you will do, when you need to find and fix some bug. You simply send a request to a broken API, and then investigate the problem with the help of debugger. That is the simplest approach and it works perfectly fine, so why would i complain about it? Well, the main reason is the amount of time and manual work needed to start the debugging process. Time to reproduce bug or test some behaviour can be very different and reach a few minutes in some complex cases. When a project is large, complex or involves many people, it becomes even more relevant because makes you take the same steps again and again. AUTOMATE EVERYTHING That's when tests come to the rescue. Let`s look at a small, simple and naive example. Here's a small web API to receive a shopping list and calculate a total price for a product in a cart. I took Flask and pytest to keep the example small, but the idea is relevant to the development process in general. app.py json flask Flask, Blueprint, request flask_restplus Resource, fields, Api api = Api(version= , title= , doc= ) namespace = api.namespace( ) result = { : list(products), } product result[ ]: product[ ] = product[ ] * product[ ] result[ ] = sum(product[ ] product products) result[ ] = result[ ] / sum(product[ ] product products) result Product = api.model( , { : fields.String(required= ), : fields.Float(required= ), : fields.Integer(required= ), }) Cart = api.model( , { : fields.List(fields.Nested(Product)), }) cart = json.loads(request.data) processed_cart = calculate(cart[ ]) processed_cart flask_app = Flask(__name__) blueprint = Blueprint( , __name__, url_prefix= ) api.init_app(blueprint) api.add_namespace(namespace) flask_app.register_blueprint(blueprint) flask_app app = create_app() __name__ == : app.run(host= ) import from import from import '1.0' 'Test API' '/doc' 'carts' : def calculate (products) 'products' for in 'products' 'total' 'quantity' 'price' 'total' 'total' for in 'average' 'total' 'quantity' for in return # serializers 'Product' 'product' True 'price' True 'quantity' True 'Cart' 'products' @namespace.route('/cart/') : class CartResource (Resource) @api.expect(Cart, validate=True) : def post (self) 'products' return : def create_app () 'api' '/api/v1' return if '__main__' '0.0.0.0' test_cart.py pytest .app app app.config[ ] = client = app.test_client() client data = { : [ { : , : , : }, { : , : , : } ] } res = client.post( , json=data) res.status_code == res.json[ ] == import from import @pytest.fixture : def client () 'TESTING' True yield : def test_valid_cart (client) 'products' 'product' 'milk' 'price' 10 'quantity' 1 'product' 'bread' 'price' 6 'quantity' 2 '/api/v1/carts/cart/' assert 200 assert 'total' 22 Command to run application , to run tests - python app.py pytest The application will work only with correct input data, if i'll send empty list of products, i'll get 500 error Here's when i use curl first time. curl -X POST \ http://localhost:5000/api/v1/carts/cart/ \ -H \ -d 'Content-Type: application/json' '{ "products": [ ] }' I'm not gonna provide full traceback, only valuable part. Last lines from traceback below. File , line 43, post processed_cart = calculate(cart[ ]) File , line 20, calculate result[ ] = result[ ] / sum(product[ ] product products) ZeroDivisionError: division by zero #....... "/app/app.py" in 'products' "/app/app.py" in 'average' 'total' 'quantity' for in To fix this we can add validation for input data, let's start from changing API model, adding to Cart min_items=1 products Cart = api.model( , { : fields.List(fields.Nested(Product), min_items= ), }) # app.py 'Cart' 'products' 1 After receiving same request API will return valid error Here's when i use curl second time. curl -v \ http://localhost:5000/api/v1/carts/cart/ \ -H \ -d * Trying 127.0.0.1... * TCP_NODELAY * Connected to localhost (127.0.0.1) port 5000 ( > POST /api/v1/carts/cart/ HTTP/1.1 > Host: localhost:5000 > User-Agent: curl/7.58.0 > Accept: */* > Content-Type: application/json > Content-Length: 23 > * upload completely sent off: 23 out of 23 bytes * HTTP 1.0, assume close after body < HTTP/1.0 400 BAD REQUEST < Content-Type: application/json < Content-Length: 114 < Server: Werkzeug/0.16.0 Python/3.6.8 < Date: Mon, 30 Sep 2019 11:13:59 GMT < { : { : }, : } * Closing connection 0 'Content-Type: application/json' '{ "products": [ ] }' set #0) "errors" "products" "[] is too short" "message" "Input payload validation failed" So, is used curl twice - to find issue and to verify fix. However for now not everything is fixed, i can force if sum of for all products will be 0, for example: ZeroDivisionError quantity { : [ { : , : , : } ] } "products" "product" "milk" "price" 10 "quantity" 0 So i need to fix this issue and check again, which means i will use curl 2 times more. That doesn't look like a big deal, but imagine having a long workflow, when issue checking setup will take up to 5-10-15 minutes. That means sometimes you gonna stuck for hours doing the same things over and over again. Instead of that you can write test. Just get a corrupted data and put it into test function. Add the following code to the test_cart.py data = { : [] } res = client.post( , json=data) res.status_code == #test_cart.py : def test_empty_cart (client) 'products' '/api/v1/carts/cart/' assert 400 Now you can call this in one command instead of configuring a requests in postman, curl or going over complex flow via your project web interface. pytest -s test_cart.py::test_empty_cart But this is not the only advantage you can use. Let's create a dummy test without any assertions to debug api with data, that will cause and add to function an statement. ZeroDivisionError calculate ipdb.set_trace() ipdb; ipdb.set_trace() result = { : list(products), } product result[ ]: product[ ] = product[ ] * product[ ] result[ ] = sum(product[ ] product products) result[ ] = result[ ] / sum(product[ ] product products) result #app.py : def calculate (products) import 'products' for in 'products' 'total' 'quantity' 'price' 'total' 'total' for in 'average' 'total' 'quantity' for in return Now you can run . Thanks to statement, code execution stopped at the beginning of the function, now you have access to the debugger pytest -s test_cart.py::test_zero_quantiy_cart ipdb.set_trace() calculation don't forget flag to prevent pytest from capturing stdin and stdout. Important note about pytest and debugging: -s pytest -s test_cart.py::test_zero_quantiy_cart ========================================================================================================= test session starts ========================================================================================================= platform linux -- Python , pytest , py , pluggy rootdir: /app collected item test_cart.py > /app/app.py( )calculate() result = { ---> : list(products), } ipdb> products [{ : , : , : }] 3.6 .8 -4.4 .1 -1.8 .0 -0.13 .0 1 14 13 14 'products' 15 'price' 10 'product' 'milk' 'quantity' 0 Now you can play around with debugger, and if you need to run this code again, you just run tests again. After issue is fixed, you can add some assertions to the test and leave it in your code, since it covers some case that has not yet been covered, otherwise the problem would not have appeared. In this case to fix the bug it's enough to add to field in model min=1 quantity Product Product = api.model( , { : fields.String(required= ), : fields.Float(required= ), : fields.Integer(required= , min= ), }) #app.py 'Product' 'product' True 'price' True 'quantity' True 1 data = { : [ { : , : , : } ] } res = client.post( , json=data) res.status_code == #test_cart.py : def test_zero_quantiy_cart (client) 'products' 'product' 'milk' 'price' 10 'quantity' 0 '/api/v1/carts/cart/' assert 400 The same you can do not only with ipdb, but with any debugger, for example, in PyCharm you can run tests in debug mode. Everything, that can by executed, can be also debugged. This approach also has following advantages : it always gives the same results you always have access to tests, written in the past you don't need any other software, like postman, to test your code you have access to mocks, provided by your testing framework you'll have your specific case covered with tests, when you finish your work WHEN THIS CAN BE USEFUL Here are some real scenarios when I found this approach useful. While developing some new functions i tend to create some basic code to proof the concept, then write some tests and continue development with their help. That can save a lot of time. Sometimes i don`t open anything except my IDE for a week. While having a bug you can put a breakpoint somewhere in a suspicious place, look into local context and create a test with data you found in debugger. It can also save a lot of time. While developing integration with third party API you can use tests to simplify and automate authorization, preparing data and so on. Also, after integration is done, you can use mocking, so your tests won`t send any real requests. I tend to use REPL(e.g. IPyhton) a lot while playing around with new libraries or functionality. If i need to perform some actions many times - it's a good idea to wrap them into a test. In conclusion, i would like to say, that this little technique not only can save a lot of time, but also can help you concentrate on your code and avoid frustration due to the constant repetition of the same actions. Coding feels much more enjoyable, when you actually do coding.