jack: (Default)
[personal profile] jack
You know that weird feeling where your tests sometimes pass and sometimes don't, and you eventually realise they're not deterministic? But it took a while to notice because you kept changing things to debug the failing tests and only slowly realised that every "whether it succeeded or not" change didn't follow changing the code?

In this case, there were some failing tests and I was trying to debug some of them, and the result was the same every time, but only when I ran a failing test by itself and it passed did I realise that the tests weren't actually independent. They weren't actually non-deterministic in that the same combination of tests always had the same result, but I hadn't realised what was going on.

And in fact, I'd not validated the initial state of some tests enough, or I would have noticed that what was going wrong was not what the test *did* but what it started with.

I was doing something like, there was some code that loaded a module which contained data for the game -- initial room layout, rules for how-objects-interact, etc. And I didn't *intend* to change that module. Because I'm used to C or C++ header files, I'd forgotten that could be possible. But when I created a room based on the initial data, I copied it without remembering to make sure I was actually *copying* all the relevant sub-objects. And then when you move stuff around the room, that (apparently) moved stuff around in the original copy in the initialisation data module.

And then some other test fails because everything has moved around.

Once I realised, I tested a workaround using deepcopy, but I need to check the one or two places where I need a real copy and implement one there instead.

Writing a game makes me think about copying objects a lot more than any other sort of programming I've done.

Date: 2017-10-16 04:37 pm (UTC)
mtbc: photograph of me (Default)
From: [personal profile] mtbc
Could switch to a purely functional language. (-: This afternoon a colleague tracked down an integration test issue: a Java test was leaving something behind in the database that it turned out confused an apparently unrelated Python test. Too much non-determinism about.

Date: 2017-10-16 07:39 pm (UTC)
andrewducker: (Default)
From: [personal profile] andrewducker
I'd go with every test recreating everything from scratch.

And also as much as possible being immutable.

Date: 2017-10-16 09:47 pm (UTC)
andrewducker: (Default)
From: [personal profile] andrewducker
I'm not familliar with the language you're using, but NUnit (for instance) has the ability to run each test class in its own appdomain, so that even statics aren't shared.

If you're using static (module-level?) variables, and that's not possible, then you're in trouble, certainly.

Date: 2017-10-16 10:13 pm (UTC)
andrewducker: (Default)
From: [personal profile] andrewducker
I don't know much about Python, but I think I've got this straight:

You've got a "helpers" class which returns an object, but it's not a _new_ object each time, it's a single object which gets returned every time (i.e. "create_blah_object" should be renamed "_return_instance_of_blah_object").

Which means that changing it causes those changes to break things.

In that case I'd either actually create a new Blah every time that method is called, or if that's not how it's supposed to run in production, I'd isolate the tests from each other, possibly by running each test separately from the script (although that will incur Python startup overhead).

Writing code so it's easily testable is _hard_. It's the main reason we use Dependency Injection for our C# code at work.

Date: 2017-10-22 08:24 am (UTC)
andrewducker: (Default)
From: [personal profile] andrewducker
Finally getting back to this (Don't have DW access from work, and was busy most evenings, sorry!)

The advantage of Dependency Injection, when it comes to tests, is that it tends to push you towards a stateless design - or, at least, one where state is immutable by default, so you know when you have to work around it.

Although, in this case, your design should have been doing the right thing, and only didn't because of an error.

Dependency Injection

Date: 2017-10-17 10:16 am (UTC)
andrewducker: (Default)
From: [personal profile] andrewducker

If you've got "Car" object and the "Repair" method on it needs to call a "Mechanic" object which can then "Fix" it, then your Car has a dependency on something which has a "Fix" method. Using an interface to specify that helps, I'd have thought, as now multiple different classes can be used, in different situations. But not using DI - or, indeed, not using interfaces, doesn't mean that you don't need the mechanic object to implement that "Fix" method, because your Car object is calling it. I can't see how you can get around that.

If your only objection is that the object which creates the Car needs to know what kind of Mechanic to pass in to the Car, then I'm a bit confused - because that's now how I'm used to using Dependency Injection.

We're using Castle Windsor (in C#). Where I can specify something like:

var utilitiesAssembly = AllTypes.FromAssemblyContaining(typeof(ConfigurationProvider)).IncludeNonPublicTypes();

container.Register(utilitiesAssembly.Where(e => e.Name.EndsWith("Provider")).WithService.FirstInterface());

And that will go off and find my MathsProvider, my TextProvider, my DogProvider, and my CthulhuProvider classes, and register them as the default provider for their first interface.

And I can set up my ChthuluProvider (which, obviously, is my main class, from which all other things are controlled) to either have a "IDogProvider" property, or take a "IDogProvider" in its constructor.

Then I can say var myCthulhu = container.Resolve()

and it will resolve the ICthulhuProvider to CthulhuProvider, notice that that needs an IDogProvider, resolve that to a DogProvider, notice that that needs an IMathsProvider, resolve that to MathsProvider, and so on, until the entire chain is resolved.

And none of those classes know anything about dependency injection. Cthulhu just knows he needs a dog for his terrible plans, and so gets one. And the dog needs maths for its strange angles, so it gets that.

And now, when I'm writing unit tests I can use a mocking utility (like RhinoMocks) to create alternate objects which respond in specific ways when they're called. And Cthulhu has no idea that his Dog is now actually a cardboard cutout designed to test what happens if things get really fractal.

Re: Dependency Injection

Date: 2017-10-22 08:35 am (UTC)
andrewducker: (Default)
From: [personal profile] andrewducker
One way is that the "send" function or the "PersonalisedMarketingEmail" class instantiates those other classes itself. This exhibits all the problems that DI fixes.

Another possibility is that whatever calls "PersonalisedMarketingEmail::send" provides a pointer to instances of those classes. This is a lot better because if the caller wants to provide a slightly different version of them, it can do so, and PersonalisedMarketingEmail doesn't need to know anything about it.


Those are two options. The third is that the dependency is injected at instantiation time. Which is what my example above was trying to lay out.

That when you create a PersonalisedMarketingEmail object you do so using the DI framework, and it works out that it's dependent on EmailSender and then passes that into the constructor.

I don't speak Python, but with a little Googling and some guesswork I reckon that you'd have something like:
class PersonalisedMarketingEmail:
def __init__(self, EmailSender)

And then you'd tell the DI to give you a PersonalisedMarketingEmail and it would magic one up, complete with EmailSender.

Which seems to be something like what Spring Python does:
http://springpython.webfactional.com/1.1.0/reference/html/objects.html
(see 2.2.1)

Mocking in C# is fairly simple with RhinoMocks.
Fairly good example of how simple it is here:
https://www.hibernatingrhinos.com/oss/rhino-mocks

Date: 2017-10-17 07:49 am (UTC)
ewx: (Default)
From: [personal profile] ewx
You've probably discovered a bug: create_blah_object is misnamed, in that it doesn't (always) create an object.