DEV Community

Discussion on: Why local development for serverless is an anti-pattern

 
frugoman profile image
Nicolas Frugoni

It seems that unit tests are not important to you.
What kind of tests are you talking about?
Tests that target databases (production or not) are slower than mocking.
If you unit test, you can test your business logic regardless of what infrastructure you are using.
Test on a staging deployed environment is still needed for integration testing, but imho this is a step to take after unit testing.
Build and test locally (unit testing with NO connection to infrastructure (http, dB, filesystem,etc)) is much much faster than deploying to any service and also it gives you almost instant feedback and you can navigate in the code instantly using the ide.

Sorry I don't agree with this post.

Thread Thread
 
garethmcc profile image
Gareth McCumskey

Personally I am not a fan of unit testing in a serverless environment; and I wrote a blog post 2 years ago about how to do it too ... how times change. In a serverless application the amount of code you write is minimal compared to a traditional web application as the cloud services you use end up replacing a lot of the code for you. This is a good thing. And in that case, integration testing is far more important than unit testing 10 lines of code that insert an object into a database.

Build and test locally is much much faster than deploying to any service

As Yan Cui recently said in a reply to one of my tweets "Speed of feedback is great, but only when it gives you the right feedback. e.g. if you're mocking AWS SDK and supposedly testing integration with DynamoDB then the test just tells you if your mock is working.

Learning the wrong thing faster is counter-productive."

The same is true testing on your Intel i7 with 8 GB of RAM and a 4k display. That is not the equivalent of a highly distributed application run across multiple machines in potentially multiple data centers, etc.

Thread Thread
 
frugoman profile image
Nicolas Frugoni

I can see your point.
But the amount of code and complexity always grows. Unit tests helps you test your logic on isolation, it doesn't really matter if your using a potato or a Xeon processor, it should be fast since the code that's being run, should in theory don't have much dependencies and you must mock each class' dependencies. You don't test your mocks here, you test your class in isolation of things outside of it, making different mocks for representing different cases.

This not only allows for writing tests as of it self, but allows you to have a good, scalable, easy to maintain codebase since you must use dependency inversion principles. Also TDD is possible, ci/cd is more reliable, etc.
Aaanyhow, this is deviating a bit I think from the post's argument.

Thread Thread
 
garethmcc profile image
Gareth McCumskey

In a serverless application, the logic is often a part of the infrastructure. An example of this is that you may have two services; lets call them a customer service and an order service. If the customer service receives a request to update customer details, all unfulfilled orders for that customer need to also have the customer details updated. In that case you use API Gateway to receive the initial PUT request to update customer data, the change is made in DynamoDB by a Lambda. That insertion triggers a DynamoDB stream entry which triggers a Lambda function. The Lambda pushes the DynamoDB action into EventBridge. The order service has a Lambda listening for customer change events and queries the orders table for all orders for that customer and performs the update. No unit test can test that entire flow and each lambda is perhaps 8-10 lines long.

Thread Thread
 
frugoman profile image
Nicolas Frugoni

Your right about non-unit tests capable of testing that entire flow, but again, that's not even a unit test.

Unit tests in this cases would be something like this:

On the order service you'll test the method 'onCustomerUpdated(customer)'

There's a bunch of things you can test depending on the use case.
For example, if you support in memory cache as well as the dynamo, you can unit test that when something calls the onCuatomerUpdated method (in production the caller would be the infrastructure itself), then check if the cache is updated as well as the dB, but using abstraction on this method.

Example using pseudocode-js

const cache = inmemoryRepository
const dB = DynamoDBRepository()
Function onCuatomerUpdated(cust) {
DB.update(cust)
.then(cache.update(cust))
.then (return 'success')
}

In a unit test environment, when you create that class to test it you would replace the dB and cache variables with mocks and you can verify if they were called in order, with what data and so on.

Sorry if there's anything badly written, I'm on my phone rn

Thread Thread
 
frugoman profile image
Nicolas Frugoni

You can imagine that if those services belong to different teams, each team would like to be sure that their code works as they intend regardless of how it's called. Some case would call that method my using a rest API from a client, maybe some other case would be the infrastructure itself calling it.

Abstraction and independence are key here I think

Thread Thread
 
frugoman profile image
Nicolas Frugoni

Side comment: I do use serverless and I absolutely love it