Hacker Newsnew | past | comments | ask | show | jobs | submit | lelandbatey's commentslogin

I feel like the #1 reason mocks break looks nothing like this and instead looks like: you change the internal behaviors of a function/method and now the mocks interact differently with the underlying code, forcing you to change the mocks. Which highlights how awful mocking as a concept is; it is of truly limited usefulness for anything but the most brittle of tests.

Don't test the wrong things; if you care about some precondition, that should be an input. If you need to measure a side effect, that should be an output. Don't tweak global state to do your testing.


> you change the internal behaviors of a function/method and now the mocks interact differently with the underlying code, forcing you to change the mocks

Rarely should a mock be “interacting with the underlying code”, because it should be a dead end that returns canned data and makes no other calls.

If your mock is calling back into other code you’ve probably not got a mock but some other kind of “test double”. Maybe a “fake” in Martin Fowler’s terminology.

If you have test doubles that are involved in a bunch of calls back and forth between different pieces of code then there’s a good chance you have poorly factored code and your doubles are complex because of that.

Now, I won’t pretend changes don’t regularly break test doubles, but for mocks it’s usually method changes or additions and the fix is mechanical (though annoying). If your mocks are duplicating a bunch of logic, though, then something else is going on.


To fully show my hand: What I do not like are mocks which have you outline a series of behaviors/method calls which are expected to be called, typically with specific input parameters, often with methods in order. In python, this looks like setting up Mocks and then using `assert_called` methods. In Go, this means using Gomock-generated structs which have an EXPECT.

A test should not fail when the outputs do not change. In pursuit of this ideal I often end up with fakes (to use Martin Fowler's terms) of varying levels of complexity, but not "mocks" as many folks refer to them.

[0] - https://docs.python.org/3/library/unittest.mock.html#unittes...

[1] - https://pkg.go.dev/github.com/golang/mock/gomock


So this I agree with. Mocks are often used to over-constrain and end up validating that the implementation does not change rather than does not regress.

There are some specific cases, such as validating that caching is working as expected, where it can make sense to fully validate every call. Most of the time, though, this is a pointless exercise that serves mostly to make it difficult to maintain tests.

It can sometimes also be useful as part of writing new code, because it can help validate that your mental model for the code is correct. But it’s a nightmare for maintenance and committing over-constrained tests just creates future burden.

In Fowler terminology I think I tend to use Stubs rather than Mocks for most cases.


Most of the real world is about manipulating the real world. For algorithms it is fine to say depend on the pure inputs/outputs. However what we care about is that global state is manipulated correctly and so the integration tests that verify that are what are important. In most cases your algorithm shouldn't be unit tested separately since it is only used in one place and changes when the users change: there is no point in extra tests. If the algorithm is used in many places comprehensive unit tests are important, but they get in the way when the algorithm is used only once and so the tests just inhibit changes to the algorithm as requirements change (you have to change the user, the integration tests, and the unit tests that are redundant).

As such I disagree. Global state is what you should be testing - but you need to be smart about it. How you setup and verify global state matters. Don't confuse global state above with global state of variables, I mean the external state of the program before and after, which means network, file, time, and other IO things.


IO and global state is also just inputs that can be part of arrange-act-assert. Instead of mocking your database call to always return "foo" when the word "SELECT" is in the query, insert a real "foo" in a real test database and perform a real query.

Again I've heard "but what if my database/table changes so rapidly that I need the mock so I don't need to change the query all the time", in which case you ought to take a moment to write down what you're trying to accomplish, rather than using mocks to pave over poor architectural decisions. Eventually, the query fails and the mock succeeds, because they were completely unrelated.

So far I've only seen mocks fail eventually and mysteriously. With setups and DI you can treat things mostly as a black box from a testing point of view, but when mocks are involved you need surgical precision to hit the right target at the right time.


> global state

In my experience global state is the testing bug farm. Tests that depend on global state are usually taking dependencies they aren’t even aware of. Test initializations grow into complex “poke this, prod that, set this value to some magic number” setups that attempt to tame the global state but as global state grows, this becomes more and more difficult and inconsistent. Inter-test dependencies sneak in, parallelism becomes impossible, engineers start turning off “flaky” tests because they’ve spent hours or days trying to reproduce failures only to eventually give up.

This sort of development is attractive when starting up a project because it’s straightforward and the testing “bang for the buck” is high. But it degrades quickly as the system becomes complex.

> Instead of mocking your database call to always return "foo" when the word "SELECT" is in the query, insert a real "foo" in a real test database and perform a real query.

Consider not sprinkling “select” statements throughout your code instead. This tight coupling makes good testing much more difficult (requiring the “set all the global state” model of testing) but is also just generally not good code structure. The use of SQL is an implementation detail that most of your code shouldn’t need to know about.

A thin layer around the DB interactions gives you a smaller set of code that needs to be tested with state, gives you a scoped surface area for any necessary mocking, makes it much easier of you need to change storage systems, and also gives you a place that you can reason over all the possible DB interactions. This is just good separation of concerns.


You didn't use global state in the same sense that I did. I mean global as in state of the entire world, not just the computer you are on.

I tamed our inter-set dependencies by doing things like starting dbus on a different port for each tests - now I can test with real dbus in the loop and my tests are fast and isolated. We have a strict rule of what directories we are allowed to write to (embedded system - the others are read only in production), so it is easy to point those to a temp dir. It was some work to set that up, but it tames most of your issues with global state and allows me to verify what really counts: the system works.

For a CRUD web app your database separation of concerns makes sense. However in my domain we have lots of little data stores and nobody else needs access to that store. As such we put it on each team to develop the separation that makes sense for them - I don't agree with all their decisions, but they get to deal with it.


Sure. I wasn’t responding to your statements but I can understand what you mean. If your code manipulates the physical world (and not in a “sets this bit on a disk” sort of way) then you have to validate that action. Whether that valuation should be decoupled from the business logic that drives that piece really depends on the complexity of the system. At some point you are going to do full integration valuation so it’s a question of balance. How much is tested that way vs more isolated.

Tests that work and verify the system works are the Pri0 requirement. Most of the conversations about how best to test are structured for the benefit of people who are struggling with meeting the Pri0 because of maintainability. With enough effort any strategy can work.

> However in my domain we have lots of little data stores and nobody else needs access to that store.

If the little data stores are isolated to small individual areas of code then you probably already have the necessary isolation. Introducing the lightweight data store isolation layer might be useless (or not, context dependent). Now if these individual areas are doing things like handing off result sets to other code then I would have something different to say.


I don't understand the "but what if my database/table changes so rapidly that I need the mock so I don't need to change the query all the time". Are they changing your database schema at runtime (not just software update time when you can do migrations)? Otherwise you should have a test helper that creates your entire database schema so that when it changes you can update the schema in one place and all tests are re-run against the new one. (you should also have some insert common test data helpers that are easy to update as needed should the new schema affect the changes)

I haven't seen mocks fail mysteriously. I've seen them fail often though because requirements change and instead of updating the callers (generally a small number) you end up with 200 tests failing and give up because updating all the tests is too hard. Mocks are always about implementation details - sometimes you have no choice, but the more you can test actual behavior the better.


I see a lot of times people (read: me) are lazy and make a mock that does not have anywhere near the behavior of the original. It's more like a very partial stub. I will mock an api with 20 possible calls with the 2 that I use. Unsurprisingly, this mock is closely tied to the current implementation.

Really only two kinds:

- Energy generation and

- Expending energy to convince the folks generating energy to give you money for activating their neurons (food service, entertainment, tourism, transportation, sales).

Any other fun ways to compartmentalize an economy?


The blog in question, right when posting seemed to pick up: https://neverseconds.blogspot.com/2012/05/

The comparison school lunch from Finland looks lovely. It's a shame that many school lunches are meals that we wouldn't pick for ourselves.

It's a simple test: would I want that for my lunch? For most of the photos, it's a no.


Looking at a video demo of Niri for an example: https://github.com/YaLTeR/niri

Conceptually, it's like an infinite 2D canvas windows, divided into strips (strip is a workspace), and you then scroll through an infinite ribbon of windows in each strip.

Seems interesting, but also slower and less flexible than traditional tiling WMs (least of all because of the slow scrolling animations, but also because it seems to prefer scrolling instead of jumping-towards).

Like most of the 'tiling with gaps' patches I see, these feel like trying to look fancy without necessarily delivering big value. I'd be interested to hear why people want a scrolling WM. Is it merely more visually pleasing?


It's the same thing as a tiling WM, with all the benefits. You can still tile windows vertically or horizontally. The big improvement is that if I have a view with my browser, editor, a terminal or two all tiled nicely but then all of a sudden I need to open the Gimp or a PDF for some one-off work related to what I'm working on, it just opens to the right. I can move over to it and do what I need to do without messing up the current layout and then close it when I'm done.

This is opposed to a traditional tiling WM where you'd either need to open the app in another workspace, use some stacking feature or worst of all shove the new window into the current view by resizing some other window(s) which is often not ideal.


Sounds interesting, but I still think I prefer using workspaces, simply because I can set window rules for predictability.

I never want to / have to wonder where any particular window is. Every app will always open on the same workspace, in the same position that I define + a scratchpad workspace for random one-offs that I keep floating. I'm only ever 1 key press away from exactly what I want. I know that ctrl+b gets me my browser, ctrl+t gets me to my terminal(s), etc. I don't even think about the workspace numbers or layout beyond initial configuration. Zero animations, instant switching.

In your example, if I'm on one workspace working and I need to open Gimp, I press my keybind for Gimp and it opens on the scratchpad and switches to it immediately.

It takes a lot of initial config and tweaking as you go along but once settled it's the most efficient way I've found to manage windows, in that, the windows manage themselves i no longer have to think about them at all.


That makes sense if you use application per workspace, which never made much sense to me.

I'm often working on 3+ codebases or projects at the same time, each project has a browser window with associated tabs, an instance of an editor, several terminals. So they get a workspace. "Switch to browser workspace" makes no sense if there are 3 instances of the browser open, especially when I want the browser next to my editor for live reload/API docs.


The problem with your example is that you might have Gimp, a browser with its own set of tabs, and other multi-instances of apps needed in multiple workspaces as you work on multiple projects.

In Niri, you just have these open in the each workspace off to the side. And you know exactly where each one is.

In your example, you either have to flip through multiple Gimp instances in your scratchpad or you use tab/stack containers to tile them in to existing workspaces. But you are multiple keystrokes away now because you have to go to the container and paginate through it.


You can also set window rules in Niri :-)

Wow. My work flow with a stacking WM is that I get my tiled windows how I like them, but then if I need a new window for some reason, I just open it and it plops on top of my tiled windows without interacting with them at all. Seems more productive to me.

> This is opposed to a traditional tiling WM where you'd either need to open the app in another workspace, use some stacking feature or worst of all shove the new window into the current view by resizing some other window(s) which is often not ideal.

I use Awesome Window Manager and one feature I like about it is this:

Say I've got my terminal in workspace 1, Firefox in workspace 2, and Emacs in workspace 3. There are often times I need to use either the terminal or Emacs (or both) while viewing a website. So with a keystroke, I can tell it to combine any two or three workspaces and all the windows are shown tiled together. In a sense, it creates a new temporary workspace with all 3 windows. As soon as I leave this workspace, it restores it to the original configuration. No need to move windows from one workspace to another and remember to move them back.

This is the one feature that I'm really missing from Mac OS.


I know how to send a window to another workspace but not how to combine two entire workspaces. Is that a default keystroke or something you set up?

https://awesomewm.org/doc/manpages/awesome.1.html

     Mod4 + Control + 1-9
        Toggle tag view.
It's a bit arcane written that way, but each workspace is a tag. Pressing Mod4 + Control + 2 means to show workspace 2. The effect is cumulative. If you now press Mod4 + Control + 3, it will be showing both workspace 2 and 3 simultaneously (and tiling the combined set of windows).

If you press Mod4 + Control + 3 again, it will remove workspace 3 from view.

If you now just leave to go to some workspace, (e.g. Mod4 + 5), it will only show workspace 5.

Can't live without it.


I'm still a Niri newbie, but I'm enjoying the scrolling as a ways to have "subworkspaces": when I'm working on a full-stack project, for example, I can scroll between the backend and the frontend, while arranging my windows in such a way that anything useful (e.g. the browser) remains resident on screen.

You can get similar functionality with tabbed windows, but I'm still trying to decide which workflow I prefer; scrolling feels a bit more "organic", while tabs are superior for density.


Checking the video and impressed how people remember all the programs they've running on the canvas and their location. In i3 have been using i3-renameworkspaces to know what is opened in other workspaces because kept forgetting.

Niri has an overview view to help with this. You can see all of your workspaces and their strips, and move applications from strip to strip.

I rock a 2070 super with 8GB vram and I'm still waiting for a big reason to upgrade. Games run good, and I play them at 1080p on my couch.

The steam machine will be a very good upgrade!


Echoing what others have said: just post your stuff. If you're not intentionally publicizing yourself or your work, I can nearly guarantee that no one will ever even look at your work. I've been putting up my little personal projects up on my GitHub for over ten years, and yet no one's ever come around to look at them except when I intentionally posted links to those projects on places like HN.

No one's going to look unless you ask them to look. If you already have a big audience (over 100+ people daily using things you've built) no one is going to "get curious" about your projects. So just post them so folks can see them.


Even if you ask people to look they won’t look. You really gotta sell yourself and have an influencer mindset to motivate someone to go look at code you’ve published.

This is it should be. It takes time and effort to try someone’s idea.

Regarding the fear someone does take it and claim it as their own. Who cares? You’re in no worse of a position than the code being private and then not doing it. It’s not relevant.


Just cause the AI could find the info definitely does not mean it will find and apply that knowledge correctly to solve a problem.

I find AI shockingly bad ad searching the web, as SEO blogspam sites heavily pollute AI context windows, while relevant and important resources are typically very densely presented reference material which must be constantly revisited.


It doesn’t need to. It has already all the fundamental knowledge it needs. Just set it up on a system with an editable proc file system and it would be able to figure it out.

Yes, new major airports (rare as they are) do try to acquire large areas of land, larger even than they think they need now, in anticipation of future expansion. However, for scenarios like this, there's limited utility to making the runway longer "just in case." They already pick runway sizes "big enough and then some" as the minimum to even bring planes of each size to an airport. So there is margin.

But no matter the margin, a plane can always crash on the wrong side of any fence. And people will always build right up to wherever you put the fence as closer to the airport is more convenient for everything airport related.


This is also a thing in X, not only Wayland.

An ebike weighs less than a motorcycle by at least half (for super lightweight motorcycles) or less than 1/6th the weight. So a fast ebike is about as dangerous as merely the human person +100lbs traveling at speed.

Thus, less energy to transmit to a pedestrian


100 pounds of bike plus 150 pounds of person hitting a pedestrian at 30+ mph is still going to do cause serious injuries to both of them.

But it's really a moot point because there are essentially zero motorocycles travelling on sidewalks, bikepaths, and trails where pedestrians are going to be concentrated, while it's a free for all for e-bikes.

In general, motorcycle/pedestrian accidents are pretty rare. Statistically, motorcyclists are most likely to injure or kill themselves rather than bystanders.


Yeah, it's not going to be as bad as a 300lb bike and 150lb person with a fuel tank in the back...

There are lots of gas powered motorcycles in the bike lanes where I live. Not legal, but nobody enforces it.


And still fatal

https://www.ctvnews.ca/vancouver/article/pedestrian-dead-aft...

In this case it was a bicycle and not an ebike. That said, anecdotally, many ebikes I see regularly travel faster than the people powered versions


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: