4 ms·
Right, marking methods as virtual is the other route I saw. Are most C# codebases opting to do that rather than add interfaces? It feels weird to edit signature
by great_cormorant 4y ago
Right, marking methods as virtual is the other route I saw. Are most C# codebases opting to do that rather than add interfaces? It feels weird to edit signatures like that for testability, but maybe it's just what I'm used to - I'm putting all of my objects in constructors already for testability's sake, and I'm no stranger to making a factory or two.
VSCode has been my way forward for file-based editing so far. It's not so bad - just feels like I'm doing things that I ought not to be when I'm searching for DLLs or a random "scripts" folder in the root folder of our repo in Rider. In IntelliJ IDEA, all of the folders are just sitting there, ready for quick edits.
I think C# overcommitted on interface-driven design. It's good in some instances, but the more I work in code the more I think that the majority of it is needless and oftentimes harmful to maintaining a healthy code base.
Thanks for the pointers! Nsubstitute looks cleaner than Moq at first glance.
- bearzdev 4y agoThat is a good question. I'm not sure. I've seen a lot interface usage for testing web apps or backend services at companies when I was doing consulting work. I personally use stubs for higher reuse, favor integration/functional tests over units, and InternalsVisibleToAttribute to allow the use of internal classes / methods from test assemblies. Its been a long while since I reached for a mocking library. I probably use structs, statics, and extension methods more than the typical dotnet dev. And for DI, I have no qualms just using concrete classes or base classes. I also built my own extensions to xunit to enable DI in test methods, since I do more integration tests. Extension methods for interfaces can be very powerful along with the newer default interface feature. So using that where it makes sense, I get. In dotnet itself, interfaces are only heavily used for key extension points, so you see them more enforcing specific idioms like IComparable<T>, IReadOnlyList<T> or adapter/extensions for System.Data.x, Microsoft.Extensions.x, and Asp.net core MVC. For the adapter types of things there is generally a base class that implements key interfaces and you can create stubs or mocks from those. For the files... for stuff in the root folder like .editorconfig, gitignore, etc. I generally create a virtual Solution folder and add those files to it. For folders with larger amounts of files, I sometimes create an empty project or use specialized project for it like node or powershell project which can be installed as VS extensions, especially if its for a project where the team lives in Visual Studio. That said, I do most of my coding in JetBrains rider or vscode these days and keep a terminal open. When I'm on a windows box, I have nano and neovim installed, so I can just quickly edit scripts that way or just do code /path/to/file as needed.
- diarrhea 4y agoReally liking your approaches and wish our code base followed them more as well. Mocking leads to “interfaces everywhere”, I agree. The latter also results from the attitude of putting interfaces all over, even if there’s just a single concrete implementation that makes sense at any point in time, like a file hashing routine (which of course should just be a function but that’s not a thing in C#). Dependency inversion gone overboard? My biggest qualm with mocking is setting up a detailed test, where every method called is specified, alongside their order etc. You’re reimplementing the entire method essentially. Those tests I despise.
- Rapzid 4y agoThe best way IMHO is to start simple and then add abstractions and interfaces over time. That will mean that, yes, when you come in to a project late there will be lots of those... There are other practical reasons for using interfaces other than just "patterns" and "testing" though. Perf is one; you can avoid a lot of unnecessary mapping by being able to pass concrete types between modules when the receiver is accepting a shape instead of a concrete type...