| ▲ | tormeh 15 hours ago |
| I don't know much about C#, but in Rust this is very much not the norm. In fact, there are technical limitations associated with async traits. This sometimes allowed us a reprieve from the madness, but only sometimes. I guess you can write enterprise Java in any language. The entire idea was to make it easier to mock components and therefore easier to test code, however all the code connecting the components became untestable, so we were back to square one, struggling to meet our test coverage quota because of the massive amounts of boilerplate. |
|
| ▲ | zelphirkalt 15 hours ago | parent | next [-] |
| The easiest thing to test will always be pure functions. Many people don't realize this, and how clean it can make your tests look. Provide input, get return value, assert/check it. Sure, at the end of the day you have some IO somewhere. But that will usually be a smaller part of the code base. Codebases that make testing more difficult than that, are making it unnecessarily complicated. Sometimes you depend on some library that forces you or heavily nudges you into another style, that can happen. But what one wants to avoid is a codebase, where one has to know to mock 5 other things because of their side effects. |
| |
| ▲ | MangoToupe 13 hours ago | parent | next [-] | | > But that will usually be a smaller part of the code base. Testing how IO composes makes up most of what you want to test because it's such a difficult problem. Reasoning about this in terms of size of the codebase doesn't make sense. | | |
| ▲ | ffsm8 9 hours ago | parent [-] | | Thing is though, most of the high level languages have that part "solved" via libraries... Hence lots of people don't see the need to test it, as they expect the library to have sufficiently tested already. That leaves your tests mostly centered around your domain/business logic Personally I'm just doing web api dev/backend atm and have to say that at least in this domain, pretty much everything actually hard is solved. The only difficulty is the "interesting" architecture decisions people like the OP introduce, making inherently trivial problems into multi week endeavors which need coordination between dozens if not hundreds of devs | | |
| ▲ | MangoToupe 8 hours ago | parent [-] | | > Thing is though, most of the high level languages have that part "solved" via libraries...
> ...
> Personally I'm just doing web api dev/backend atm and have to say that at least in this domain, pretty much everything actually hard is solved. Color me extremely skeptical! |
|
| |
| ▲ | tormeh 13 hours ago | parent | prev | next [-] | | Exactly. Divide the code in impure and pure functions. The pure functions can be easily unit tested. The impure ones can often be integration tested. The rest you'll just have to live with (or cover with whole-process integration tests). For tests spanning larger chunks of your code base it might be worth it to mock impure code. Never mock pure code - that's madness. | |
| ▲ | 9rx 12 hours ago | parent | prev [-] | | Trouble is that in an application the pure functions are just implementation details that don't need to be tested. They get tested by virtue of a correct implementation being necessary to correctly run the application. A library can be a little different story, as there the public interface is quite likely to be pure, but I expect most codebases found in the wild are applications. The discussion happening here seems to be directed at applications. Granted, it appears Rust gets a lot of use as a cross-language library provider, where the application glue is written in other languages. Perhaps that's why? |
|
|
| ▲ | littlecranky67 15 hours ago | parent | prev | next [-] |
| What is the default way in Rust to write REST endpoints and have the REST endpoint use/create handles to your database transaction that is bound in scope to the underlying HTTP request? (i.e. transaction lifetime and commit/rollback is linked to the HTTP request succeeding) |
| |
| ▲ | tormeh 13 hours ago | parent [-] | | Often each API route will have its own handler function. That function will - usually through many layers of indirection and abstraction - launch queries towards your database. | | |
| ▲ | littlecranky67 12 hours ago | parent [-] | | That describe a REST API implementation design, but doesn't really answer the particular question: How is the scoping implemented, i.e. how would any given Rust REST API framework couple a Db transaction to a HTTP scope. I mean, I know how that would look like if the framework ofered you no abstraction or DI whatsoever. You would pass the transaction (and maybe database handle) through all sorts of functions, create some sort of context object (that holds all sort of references to the http connection, database, transaction and whatnot, and call everything manually. Eventually you will end up building a similar custom-made abstraction that the built-in DI container in ASP.NET does. But I would expect there are some frameworks for rust that already deliver that. | | |
|
|
|
| ▲ | wiseowise 14 hours ago | parent | prev [-] |
| How do you fake implementation without using interfaces/abstract classes? |