TDD: why might it be wrong to let app code know it is being tested, not run?

后端 未结 5 466
说谎
说谎 2021-01-19 19:35

In this thread, Brian (the only answerer) says \"Your code should be written in such a fashion that it is testing-agnostic\"

The single comment says \"Your code shou

5条回答
  •  臣服心动
    2021-01-19 19:49

    I read all these answers quite closely and they are all helpful. But perhaps I should reclassify myself: I appear to be becoming a low-intermediate TDD practitioner, rather than a newb. A lot of these points and rules of thumb I have already assimilated, either by reading or by sometimes baffling, occasionally bitter but always instructive experience over the past 6 months or so.

    Carl Manaster's analogy with the Volkswagen scandal is seductive but slightly inapplicable, perhaps: I am not suggesting that the app code should "detect" that a test is happening and alter its behaviour as a result.

    What I am suggesting is that there are one or two knotty, bothersome low-level problems where you might want to use this tool in a way that does not interfere in any way with the cast-iron rules and "philosophy" of TDD.

    Two examples:

    I have a few cases in my code where exceptions are thrown, and tests where I want to check they are thrown. Fine: I go doThrow( ... ) and @Test( expected = ... ) and everything works fine. But during a production run I want an error message to be printed out with a stack trace. During a test run I just want the error message. I don't want the logback-test.xml to suppress error-level logging completely. But apparently there is no way to configure a logger to prevent printing out the stack trace.

    So what I can do is to have a method like this in the app code, contrived solely for testing:

    boolean suppressStacktrace(){ return false; };
    

    ... and then I use that as a test for a given LOGGER.error( ... situation, and then mock that method to return true when I want to provoke that exception during testing.

    Secondly, the rather specific case of console input: BufferedReader.readLine(). Substituting another InputStream for System.in and feeding it with a List of different Strings which will be served up once per readLine is a right pain in the provberbial. What I have done is to have a private field in the app class:

    Deque inputLinesDeque;
    

    ... and a package-private method to set this with an List of input lines, which can then be popped until the Deque is empty. During an app run this Deque is null, so an if branches to br.readline() instead.

    These are just 2 examples. No doubt there are other situations where the ultra-purist approach comes at too high a price, and arguably procures no real benefit.

    However, I appreciate davidxxx's superior definition of one of the TDD 10 commandments: "thou shalt not create methods to suit your tests and that open the API of the application in an undesirable way". Very helpful: food for thought.

    later

    Since writing this a month ago I've realised it's far from impossible to extend and modify logback classes... I assume it wouldn't be too difficult to make your own logback class that would indeed accept a configuration flag in logback-test.xml to "supress stack traces". And of course this bespoke logback class wouldn't have to be exported when you make an executable jar of your app ... but again, to me this comes in the category of "jumping through hoops". How "pure" does app code really need to be?

提交回复
热议问题