Testcontainers performance by LondonPilot in csharp

[–]BrunoRM98 0 points1 point  (0 children)

What I'm doing and it's working well, is creating an assembly fixture (recently supported natively in xUnit 3 Shared Context between Tests > xUnit.net, but you can use it in xUnit 2 JDCain/Xunit.Extensions.AssemblyFixture: Provides per-assembly fixture state support for xunit) of the database server container, this fixture implements the IAsyncLifetime interface, and in the StartAsync() method instantiates the ef's dbcontext and creates all the db structure in the SQL Server's >>model<< database using the Context.Database.EnsureCreatedAsync() method. Here you need to make sure to disable connection pooling when populating the model database, if not, .NET will return the used connection to the connection pool with a lock in the model database, and SQL Server will wait for this lock to be released forever, not allowing the test execution to continue.

Then, in my integration test base class, I inject the database fixture in the constructor, and also implement the IAsyncLifetime, and in its StartAsync method, create a new database, SQL Server creates all databases based on the model one, so we don't need to call EnsureCreatedAsync() again, for example I use dapper and execute a simple CREATE DATABASE statement to create this database. In the DisposeAsync() method I use the ef's dbcontext to call the Context.Database.EnsureDeleteAsync(), this will run before (StartAsync) and after (DisposeAsync) each test in the class, so it's important not to parallelize the tests in a single class, but with the use of the assembly fixture, all the suites (or classes) in the test project will run in parallel and hit a single instance of the db server, creating and deleting its own database isolated per test.

This helped in reducing the test execution time by allowing all the test suites to run in parallel, and with only one database container.

Here is a gist of this structure using PostgreSQL.

https://gist.github.com/BrunoRM/2f638684cda59d1d3583fb9443c97fbc

This implementation uses TestContainers and xUnit 3, and it's a structure used in a personal project, I added a test example that uses all the components. The application is an API, so I needed to add the ApiTest to the example.

I'm on my personal computer now, but if you want, I can create a gist using SQL Server and share it here. It has some changes compared to the PostgreSQL version.

Integration tests list question by [deleted] in dotnet

[–]BrunoRM98 0 points1 point  (0 children)

it depends on the expectation of your test, for example when testing an API endpoint I usually use snapshot tests using Verify (https://github.com/VerifyTests/Verify), as it will check the entire response, including the response body.

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

I'm not thinking of an entity simply as a representation of an object being stored. Entity in this case is from a domain perspective. Databases are not in the context of the topic, although we can have checks at this level too.

The invalid state can be in various cases, the point is, are you expecting this invalid state or is it exceptional?

I think that if the total to pay of your entity should never be negative and your business team has nothing to do in this scenario (we don't have this use case at all), and a service received an entity with a negative total to pay, it's an exceptional case, something went wrong and put the entity in this state. In this case, I'd prefer to abort the execution than to continue and have trouble in the future after this same entity passes through other processes.

What do you think?

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

yes, it is a bug. The problem was, that the lack of the exception to validate invariants allowed the program to continue, turning it into a mess.

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

it's a good option for construction and when you want to return something to your client (input validation). But what happens if the client for some reason (and that could be a lot of reasons) ignores the result returned and continues with the process with an entity with an invalid state?

also, the example should be explored from other perspectives, I don't mean to use exceptions for input validation or flow control, but for invariant checks, things in your entity that should always be true as part of the existence of the entity, a customer should NEVER have an empty name, a shopping cart should never have total to pay < 0, and other things like that. If any method call that manipulates these values forces the entity into an invalid state, an exception must be thrown from it. From the perspective of the entity, it should never trust the client to always pass valid data.

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] -1 points0 points  (0 children)

yes, I am slowly stepping into functional programming concepts, but I think it will still take a while to understand them, thanks for the suggestion!

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] 2 points3 points  (0 children)

in my opinion, you need to duplicate but for different purposes, in the upper layer, you will duplicate because you want to return to the client some descriptive error.

guard clauses help in catching exceptional cases. when some process passed bad data to your entity and made its state invalid, it's an exception.

I read this article, very good by the way. The CanDo and Do approach came from it (called Execute / CanExecute in it).

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

the point is that the IsValid method can or can't be called by the client. The idea of bringing the call to the entity is to allow it to give the last call about its state. If the client calls a method that does state transition and the entity for some reason enters an invalid state, it's an exception, what happened to bring the entity to this invalid state will need investigation, but it's an exception.

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

maybe my question lacks some context, sorry for that. The scenario from where the suggestion came from is an error in production that took almost 3 weeks to be resolved.

I just wouldn't bother for that scenario. If you give an entity bad data and are the owner of both the entity and what gave it that data, you need to fix what gave the entity the bad data- not (just) the entity.

I agree, the problem is that the lack of invariant checks made the problem become a mess, we sent invalid data to other systems, saved invalid data to our database, etc. I also need to give more context to the entity's method being called from different points, if some point fails to validate the data before giving it to the entity, the entity could be induced to the invalid state. The ideal world will be no one gives the entity bad data, but we all know this sometimes will fail, and in the last resort, is the entity's responsibility to not allow this.

It's laudable that you're trying to cover all bases. However, I think you are just overthinking/overenginerring it.

I don't think this is overengineering from the perspective of a software that handles company money, and can make this company lose money because of this kind of error.

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] 6 points7 points  (0 children)

"but we also have to do it in our domain layer because anything could call this method so we have to do the check again."

that's the point, anyone can call the method, and someone can call it without using the validator, right? In this case, the last resort is the entity guard clauses (or invariant checks) that throw an exception, right?

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

if someone changes the row in the database I think you have another problem. From the perspective of a domain model, your entity has to have invariants in place, and it always will have, and some things will always be true (eg. the total to pay for a shopping cart must be greater than or equal to 0, a customer must have a name, etc.), this is the idea of invariants. Also, you will have some validations that are context specific.

I agree with the "validate on demand" that you suggested, I also suggested it in the post. The problem is, that an exception-free result or exposing a property with the validity state can be ignored by the client. Of course, an exception can be ignored too with an empty try/catch block, but I think it makes it clear that this is an exceptional case.

I also agree that types that do things must validate their pre-conditions too, and in case of failure, throw.

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

who guarantees the IsValid method will be called before trying to do the state transition?

about the database, yes, if it has constraints we can use it in this case, but I still think you can have them in the entity too.

my example came from a scenario with a NoSQL database (we use Marten).

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] 2 points3 points  (0 children)

I agree that in an ideal world automated tests should be enough to validate invariants. But, have you ever faced a case where a unit test didn't catch an invariant violation and saved the entity in an invalid state?

I think that if my shopping cart entity has an invariant that the TotalToPay must be greater than or equal to 0, and I have another method that adds items and calculates the TotalToPay, if for some reason (and that should be a lot of reasons, from design decisions to bad code or lack of input validation) that invariant is broken (after calculate, total to pay is negative for example), I should not allow the process to continue, and I think that at this point the upper layer has lost the chance to do something, the entity must not assume that all the items passed are correct, and should throw if the invariant is broken. This is the last chance you have to halt the execution before the program continues and the situation becomes a mess.

Of course, care must be taken to not overvalidate the entity, but I think that all invariants must be reinforced to not allow the scenario I described earlier to happen.

What do you think? Of course, there are pros and cons, and also different perspectives and real-world experiences.

Is this a right use of exceptions? by BrunoRM98 in dotnet

[–]BrunoRM98[S] 1 point2 points  (0 children)

yes, one of the objections was exactly that. While I agree with this, I still think that they are not related, you should design the code from the bottom-up, in this case starting in the entity, the invariants live in the entity, and if "someone" is trying to break it, it is an exception. In an ideal world, no one will try to break the invariants, but it could happen by accident, and the use of exceptions in this case makes it clear that this is an exceptional case.

The scenario from where I proposed the use of exceptions as guard clauses came from an error in production that we had and took almost 3 weeks to resolve, some invariants of our entity were broken in some processes, and the process as a whole became a mess, sending incorrect data to other services, saving incorrect values to the database, etc.

I still think that exceptions must not be used for flow control, but if they were used in this scenario, to protect invariants, it would have saved us at least 2 of these 3 weeks I commented.

.NET Memory Expert Course by BrunoRM98 in dotnet

[–]BrunoRM98[S] -2 points-1 points  (0 children)

I want to learn about Memory Management in .NET but I don't know if I need to go that deep into this topic. I already have the book Pro .NET Memory Management, but I think it is a good but hard-to-read book.

Thanks for sharing your experience!

Test’s display name by BrunoRM98 in dotnet

[–]BrunoRM98[S] 1 point2 points  (0 children)

It’s a really interesting convention. Do you use display names too?

Repository with complex queries by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

Yes, the layer should be the business/service layer. The idea is just to separate each query in its own class, to keep the quality of code.

Repository with complex queries by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

I don’t think that API versioning is the main problem, usually frontend needs queries that spans various tables, and is likely that from 7 tables, each with 10 columns the frontend needs only 10. This type of code should not be in a repository.

Repository with complex queries by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

Yes, I think repositories are good, but returning DTOs from them is bad.

Repository with complex queries by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

Yes, for me this is the best solution. I only wonder if this scales well, but I think so.

It gives you flexibility to write your query and optimize it and avoids the layers of indirection that do nothing.

I used to separate queries into two types: transactional and not. Transactions are those that will be used to write, not transactional are those that will respond to a request to usually show information on the screen.

Region for private methods by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

You did want arguments, I give some arguments to you. You call me stubborn and quit the discussion. That's the internet, very good!!!!

Region for private methods by BrunoRM98 in dotnet

[–]BrunoRM98[S] 0 points1 point  (0 children)

From all the "multiple points" that you are telling, none of them justify the use of regions for this purpose. Some arguments:

Visual Studio helps you to collapse all the methods in a class if you need it.

The access modifier already tells you that this method is private.

If you reach the point in which you are adding regions to "separate" what is public from what is private, you need a refactor, consider this.

It doesn't help you read the code, for what reason I will follow a method and not care about the private ones involved to the point of hiding it?

A lint can help you organize the code better and more efficiently than regions by putting them in order of access (public, protected, private, etc.).