Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Forgive me, this is going to sound snarky but I promise I am earnest:

> I'd also like to specify various injection points for tests right as I'm writing the code

You mean, like methods/functions?

> extract some arbitrary subset of the code and surround it with tests

You mean, like modules/classes?



Kind of, but three big problems in practice are:

- runtime state you need to initialize if your code is written in a stateful manner

- other methods/functions in different modules/classes the code you want to test calls out to

- the fact that method/function and module/class separation is (and IMO always should be) primarily driven by needs of production architecture, not testing, means that it may not be perfect for testing needs

Add to that the failure of testing tools and methodologies (like "don't test private methods" meeting "separate out duplicated or complex code into private methods"), and I feel the problems are real.

----

Here's an idea that just popped into my head right now: how about "hash-based testing"? You take a code you want to test, like:

  private Integer foo(String bar, Frobnicator quux) {
    String frob = quux.invokeMagic(bar);
    return memberApi.transform(frob);
  }
and turn it into:

  Method cut = <<
  private Integer foo(String bar, Frobnicator quux) {
    String frob = MOCK(quux.invokeMagic(bar)) AS("frob");
    return MOCK(memberApi.transform(frob)) AS (frob.length() > 3);
  }>>;
  
  //continue testing cut()
The idea being, the compiler or whatever external tooling ensures that the original method in production code, and the inline-modified method in tests, are the same with respect to some equality/hashing function that always treats expressions "foo" and "MOCK(foo) AS(bar)" as equal.

This way, you end up being able to mock everything precisely, inline, in whatever way you see fit, with your tooling ensuring that the actual code stays in sync with the test, since whenever the original method changes in any meaningful way, you'll fail the code "equality" test.

Might be a stupid idea, I welcome comments.

(INB4 testing to implementation instead of the interface - if you have to mock anything, you're already testing to implementation, and this way you can inject testing alterations precisely, instead of having to turn your architecture inside-out to support IoC/DI/whatever the current testing-enabling OOP fad is.)


I just don't experience these problems since I moved to functional style; I find it hard to remember that they even existed. Separate state from logic, separate initialization from operation, and you never have problems with initializing state. If your logic needs to perform effectful operations, separate that out using a monad. Good code structure for production is the same as good code structure for testing, because the needs of code structure are the same in both cases.

Text substitution is impossible to reason about; magic test frameworks sound like a good idea because every kind of magic sounds like a good idea in isolation, but they'll always end up getting you in trouble. Plain old code, plain old functions, parameters, and modules, always win in the end, because every bit of brainpower you can save from understanding magic is brainpower you can spend understanding the details of your actual test instead.


I'm mostly writing functional-style too these days, even in imperative languages. So this was more of a thought experiment based on the testing I've done in the past or watch being done at my $dayjob.

That said, I didn't mean text substitution, but AST transformations (or rather, AST comparisons, since my example is defined in terms of AST equality with the MOCK magic thingie making the particular part of AST be ignored for the sake of comparison).


It's supposed to be this way but in practice it doesn't seem to work. With methods/functions it's a problem when they call other functions.

So really the idea that a good design is also testable is somewhat of an approximation of reality, It has some elements of truth but at some point making your code more testable actually makes it worse, often you need to make other compromises. Then the interactions of pieces of code typically happens in much more brittle system/integration tests. YMMV, this is just my experience.

A lot of interesting pointers in the replies, thanks!




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

Search: