A <ul> is a list of things whose order makes no difference to its meaning. Rearranging a <ul> would change the presentation, not the information. Rearranging an <ol> would change both.
<ul> Players
<li> Alice
<li> Bob
<li> Carol
</ul>
<ol> Leaderboard
<li> Bob
<li> Alice
<li> Carol
</ol>
HyperText Markup Language is semantic. You're marking up a document to show what information it contains, where it contains it, and how it relates to other documents or information. Reading markup causes browsers to display things, but that's incidental.
In theory.
In practice, no one cares about semantics and the choice of tags is based on how a target set of browsers happens to display them.
Your question about who interprets markup is exactly right. In theory, you have no idea. Maybe it's a browser, maybe it's assistive software, maybe it's a browser printing, maybe it's some custom knowledge base with different views of documents for different users. In theory, you're supporting all of that by only marking up semantics and allowing the consumer to interpret them, because there isn't one right answer.
In practice, your client is Chrome.
In theory, that's irrelevant because you're using CSS to style semantic markup so it works in Chrome and still makes sense to other clients.
In practice, you're writing a web application, using a framework, and nothing in the stack wants you to do that.
There being a few edge cases where it doesn't work in doesn't mean it doesn't work in the majority of cases and that we shouldn't try to fix the edge cases.
This isn't a legal argument and these conversations are so tiring because everyone here is insistent upon drawing legal conclusions from these nonsense conversations.
We're taking about different things. To take responsibility is volunteering to accept accountability without a fight.
In practice, almost everyone is held potentially or actually accountable for things they never had a choice in. Some are never held accountable for things they freely choose, because they have some way to dodge accountability.
The CEOs who don't accept accountability were lying when they said they were responsible.
You would have an API that makes the query shape, the query instance with specific values, and the execution of the query three different things. My examples here are SQLAlchemy in Python, but LINQ in C# and a bunch of others use the same idea.
The query shape would be:
active_users = Query(User).filter(active=True)
That gives you an expression object which only encodes an intent. Then you have the option to make basic templates you can build from:
With SQLAlchemy, I'll usually make simple dataclasses for the query shapes because "get_something" or "select_something" names are confusing when they're not really for actions.
This is a better story because it has consistent semantics and a specific query structure. The db.getUsers() approach is not part of a well-thought-out query structure.
> It's the Thing module's responsibility to correctly set up the test doubles involved.
But why?
Maybe there's some fundamental difference of opinion here, because I'm thinking definitely not, no way, test-only code paths should never reach prod, and code that ships should never even know that testing is a thing that happens.
That's the trick - it is not test only code. You use the same objects, the same code.
The code has to be written so it takes in the altered unit via parameters or other DI or so it knows that the current system is set to short circuit some calls.
Ie, you could have MyClient(testHTTPClient).GetResource(foo) used in tests and MyClient(realHTTPClient).GetResource(foo). The testHTTPClient would get to the actual connection part and return a configured response or error.
Your entire logic is the same, your code could "receive" a forced 404 or timeout or 200 OK. It is up to the testHTTPClient that is only changing how the http connection is handled.
I call these unit-integration tests. You are checking all units work together while not actually working with the outside world.
You’re responding to a comment containing a method call `thing.makeThingDoerForTest(1, 2, 3)` and saying “That's the trick - it is not test only code.”
It goes a bit into the same direction rust went by shipping the unit tests usually inside the module. The thought is intriguing to keep the „mock“ setup up to date even when doing refactors. But I wonder if this solves the issue.
I tend to not use mocks. And I try to stay away from spies. These two tie the tests to close to the implementation like the article also described.
The reason why I don‘t ship test setup in production code is the simple fact that the test / spec should not be based on production code. Hard to put in words for me but the test should be impartial. It sets up its test world and run the subject in it. It should not use the subject to describe the test environment. I think this will lead to false positives.
I have an example where a coworker used constants from production to assert return values. I stated that the test can‘t use them because the test is the specification and needs to be in control what is correct and what is not. Even if that means we write duplicate string values. In this case somebody changed a const value to a wrong value. But for the test this was all fine.
What is the harm in a test only path in production? If you are an embedded systen with limited memory there is obvious harm but most code isn't that. There are other possible harms but they are less obvious and may not imply. There are also many different ways to implement this.
i did something like this where in production I have if function pointer isn't null return the result of it instead of running the production code (and an unlikely compiler directive on the if). The function itself is implemented in a test only shared library so the cost to production is low. If you can break in you can set that function - but if you can inject arbitary code we are already sunk.
`makeThingDoerForTest` is a standalone function (or static method) that never gets called in production code. I don't see why it needs to be in an entirely separate module. If you want, you could put it in a separate thing_test module, but then you'd have to expose a more powerful constructor for thing_test to access. I'd rather hide that inside the thing module, and I see no benefit to splitting this functionality across two modules just for the sake of not mixing my peas with my potatoes.
> no way, test-only code paths should never reach prod, and code that ships should never even know that testing is a thing that happens.
What's your reasoning for this?
As a counter-example, the hardware you are using right now almost certainly has test points throughout the circuitry.
Beyond all the uses the test points get during development and manufacturing,
they are essential for repair and re-calibration after being sold to the customer and put into production.
So much needless discussion because someone makes an ill thought out hot take. Most engineered objects of any substantial complexity include built in test systems. They would be impossible to build without them.
In-situ fault testing and isolation is an engineering principle that per pervasive across many domains. You want your auto manufacturer to rip anything related to tell you why it doesn't work?
You are just trying to defend a previous opinion by throwing out some acronyms to dress up your argument.
They should spin two boards, one with jtag and one without and then how would they debug the board they just removed the jtag on?
All systems are dynamic, all reliable dynamic systems use feedback, but you are arguing that engineers would rather remove those feedback mechanisms?
Honestly I'd probably resist this too. Maybe you could practice on me? Help see the benefit?
I'm seeing three main points in this advice:
1. Don't misuse mocks. (Mocks, fakes, whatever.)
2. Write testable, well-factored code with pluggable dependencies.
3. Don't use mocks at all. Use "nullables" instead.
I'm totally on board with (1) and (2) as good advice in general, no matter how you're testing. But (3) seems like an independent choice. What benefit does (3) specifically deliver that you wouldn't get with (1) and (2) and mocks instead of nullables?
I'm ready to admit I'm missing something, but I don't see it.
The beauty of the nullable approach is that when you're testing the system under test (SUT), you're testing it together with its dependencies. Not just that - you're running the real production code of the dependencies (including transitive dependencies!), just with a off switch toggled.
What the off switch does is really just prevent side effects, like making actual HTTP requests to the outside world or reading bytes from the file system. Using embedded stub makes this a breeze (another revelation for me).
For example, while building the "/v1/add-account" endpoint, you write a test for the request handler function. If you write this test using Shore's approach, you'll exercise the whole tree of dependencies, down to the leaves.
This is what is meant by sociable tests - the SUT isn't isolated from its dependencies. It's the real code all the way down, except that you're calling createNull() instead of create() to instantiate the classes. There are many benefits here, but to me the most important ones are: (1) you don't need to write mocks as separate classes, (2) you can catch errors that arise in the interplay of the various classes or modules and (3) as a result you get a lot more confidence that everything is still working after refactoring.
A sociable microtest is a little like an integration test, but you don't exercise any out-of-process dependencies (perhaps with the exception of the RDBMS) so the tests run in milliseconds rather than seconds.
You commented elsewhere that you're worried about the separation of test code and prod code. Yes, this is a bit of a holy cow that I also had trouble adapting to. It turns out, having test-focused code mixed in with your prod classes is totally fine. I'd perhaps prefer a cleaner separation but honestly it's not a big issue in practice.
I'm all aboard this, in fact it's how I like to write my "unit" tests, but still I'm unsure about this nullable and test code with prod.
What I do is I simply mock as little as possible (leaf nodes such as timers, remote calls, sometimes RDBMS/filesystem, ...). But I'm not sure what embedding the mock in the prod code gains you? I wonder if part of it is down to the language used?
For instance it says "Put the stub in the same file as the rest of your code so it’s easy to remember and update when your code changes.". Maybe it's because they're using a dynamic language? I'm using C++, so any change in interface will fail to compile the mock, making this less important. You could change the behaviour whilst keeping the same interface, but it's very rare in my experience (and definitely should be avoided).
Nullable I could see some values in some cases where you also want to be able to disable a functionality in prod. But in that case you have a function in the interface to turn it off, so you might as well use that. I can see where using Nullable in construction avoids having to expose this method through the whole dependency tree, but at the same time you lose the ability to dynamically turn in on/off.
I think the big benefit comes from hiding implementation details away from tests. Here—let me copy-paste an example I used elsewhere in this thread:
---
With mock injection:
m = new FooMock()
m.call("Bar", 1, 2)
m.call("Baz", 3)
p = new Thing(m)
actual = p.doSomething()
assert(expected == actual)
With a test-specific factory method:
p = Thing::makeTestThing(1, 2, 3) // static method
actual = p.doSomething()
assert(expected == actual)
With the test-specific factory, mocked dependencies are encapsulated by Thing. You can configure the their behaviour by passing different parameters to the factory method, but implementation details like `m.call("Bar", 1, 2)` are hidden. The test doesn't need to know that `doSomething` calls `Foo.Bar`.
I'm not sure whether the author of the article would consider `Thing` to be a nullable if `makeTestThing` uses a conventional, automatically-generated `FooMock` under the hood, but I don't think it really matters. To me, the big benefit comes from `Thing` assuming the responsibility to configure and inject its own mocks.
Thanks, this helped me understand some things. Unfortunately I don't have time to write a real reply right now, but I think I'm more convinced than before. Thanks for taking the time.
Part of testing is risk management. With mocks you run the risk of the behaviour of your mocks being out of sync with the actual systems you’re mocking. By moving the test-time behaviour closer to the runtime behaviour, you reduce that risk somewhat. If you have other ways of managing that risk or you just never see that happening, you’re good.
The value-add for (3) is that "nullables" encapsulate all the fiddly details that mocks (tend to) expose.
Here's an example. With mock injection:
m = new FooMock()
m.call("Bar", 1, 2)
m.call("Baz", 3)
p = new Thing(m)
actual = p.doSomething()
assert(expected == actual)
With a test-specific factory method:
p = Thing::makeTestThing(1, 2, 3) // static method
actual = p.doSomething()
assert(expected == actual)
With the test-specific factory, mocked dependencies are encapsulated by Thing. You can configure the their behaviour by passing different parameters to the factory method, but implementation details like `m.call("Bar", 1, 2)` are hidden. The test doesn't need to know that `doSomething` calls `Foo.Bar`.
I'm not sure whether the author of the article would consider `Thing` to be a nullable if `makeTestThing` uses a conventional, automatically-generated `FooMock` under the hood, but I don't think it really matters. To me, the big benefit comes from `Thing` assuming the responsibility to configure and inject its own mocks.
reply