, ,

Do you want to test Python based Azure Function (v2) in a DevOps build pipeline?

Posted by

Intro

You might come across some general guidance for testing python solutions in a build pipeline by doing Unit Testing and/or integration testing. This blog isn’t going to dive into specifics on how to set up either test. Instead, I want to provide a high-level overview and how compatible those tests are when it comes to building and deploying Azure Functions (v2).

Unit Testing

Let’s talk about unit testing and python solutions for a moment.  You can write against the classes and functions you want to test against in a separate file that usually is called test.py.  That file lives in a test folder as part of your solution.  The idea behind unit testing is you create mock objects that mimic classes or methods defined in your python solution. You decide in your test.py how the function should execute meaning what specific tests do you want to run within the associated python solution. You might be testing one specific function or a chain of functions that are called based on given conditions.  

When it comes to Azure DevOps, where would you place a unit test?  Usually this is part of a build pipeline, and you would see a script step that includes pytest.  Pytest is a common framework for both unit testing and integration testing. The million-dollar question is should I do unit tests against an Azure V2 Function? My answer is no you shouldn’t.  Two reasons why I don’t recommend it.

First, Azure V2 functions are decorator based and to account for those in your unit tests is quite complex.  After testing, I think decorators are loaded at import time which makes writing a unit tests while accounting for the app.route decorator isn’t possible. You can certainly bypass the decorator but that means you are refactoring your code which in my opinion, isn’t worth the effort involved.   

Second, unit tests are validating the logic of your function app.  For example, if I call an API in my azure function called goFetch() and the code actually calls an external endpoint.   When I test this as part of my unit tests, I don’t want to make external calls but want to confirm the function executes and returns json object back.   I can create mock objects to simulate this behavior hardcoding a response in json as my return statement within a test.py file.  Unit Testing is not about testing if results are successfully fetched from a backend SQL database or an external API.   It’s about simulating function calls and tests and providing simulated results.  Ensuring that based on the artificial result returned is expected and subsequent functions are called where this simulation is rinsed and repeated until the unit test is complete. 

I would stick with integration testing if you really want to go down that road.  See more below.

Integration Testing

Integration Testing is testing not only your application or function execution within your application, but also testing how your application interacts with external components.  In my Azure function (v2) series on YouTube, the azure function retrieves from Azure Key Vault, Azure SQL Database, and Entra ID.   The challenge with integration testing with an Azure Function like this one, is that you would need to ensure you run the azure function locally somewhere to do your testing.  Within a build pipeline, that would happen on an Agent which is a virtual machine that’s used during the life cycle of your build pipeline.  If it’s not a self-hosted agent, that means it’s shared and you could run into conflicts.  While I think it’s possible to do integration testing as part of your build pipeline on a self-hosted agent, the question becomes do you really need to do that?

Conclusion

For Azure Functions (v2), thier are much better alternatives over unit and integration testing within a build pipeline.  Staging slots, testing it locally prior to committing the code to a repo, or blue/green deployments if you want to test the azure function in an isolated environment.  Lots of options that are frankly better and more efficient.  

Thank You,

Russ Maxwell