What Makes a Good Unit Test? [closed]

2019-01-01 04:38发布

I'm sure most of you are writing lots of automated tests and that you also have run into some common pitfalls when unit testing.

My question is do you follow any rules of conduct for writing tests in order to avoid problems in the future? To be more specific: What are the properties of good unit tests or how do you write your tests?

Language agnostic suggestions are encouraged.

18条回答
长期被迫恋爱
2楼-- · 2019-01-01 04:47
  1. Don't write ginormous tests. As the 'unit' in 'unit test' suggests, make each one as atomic and isolated as possible. If you must, create preconditions using mock objects, rather than recreating too much of the typical user environment manually.
  2. Don't test things that obviously work. Avoid testing the classes from a third-party vendor, especially the one supplying the core APIs of the framework you code in. E.g., don't test adding an item to the vendor's Hashtable class.
  3. Consider using a code coverage tool such as NCover to help discover edge cases you have yet to test.
  4. Try writing the test before the implementation. Think of the test as more of a specification that your implementation will adhere to. Cf. also behavior-driven development, a more specific branch of test-driven development.
  5. Be consistent. If you only write tests for some of your code, it's hardly useful. If you work in a team, and some or all of the others don't write tests, it's not very useful either. Convince yourself and everyone else of the importance (and time-saving properties) of testing, or don't bother.
查看更多
宁负流年不负卿
3楼-- · 2019-01-01 04:47

Never assume that a trivial 2 line method will work. Writing a quick unit test is the only way to prevent the missing null test, misplaced minus sign and/or subtle scoping error from biting you, inevitably when you have even less time to deal with it than now.

查看更多
长期被迫恋爱
4楼-- · 2019-01-01 04:49

Most of the answers here seem to address unit testing best practices in general (when, where, why and what), rather than actually writing the tests themselves (how). Since the question seemed pretty specific on the "how" part, I thought I'd post this, taken from a "brown bag" presentation that I conducted at my company.

Womp's 5 Laws of Writing Tests:


1. Use long, descriptive test method names.

   - Map_DefaultConstructorShouldCreateEmptyGisMap()
   - ShouldAlwaysDelegateXMLCorrectlyToTheCustomHandlers()
   - Dog_Object_Should_Eat_Homework_Object_When_Hungry()

2. Write your tests in an Arrange/Act/Assert style.

  • While this organizational strategy has been around for a while and called many things, the introduction of the "AAA" acronym recently has been a great way to get this across. Making all your tests consistent with AAA style makes them easy to read and maintain.

3. Always provide a failure message with your Asserts.

Assert.That(x == 2 && y == 2, "An incorrect number of begin/end element 
processing events was raised by the XElementSerializer");
  • A simple yet rewarding practice that makes it obvious in your runner application what has failed. If you don't provide a message, you'll usually get something like "Expected true, was false" in your failure output, which makes you have to actually go read the test to find out what's wrong.

4. Comment the reason for the test – what’s the business assumption?

  /// A layer cannot be constructed with a null gisLayer, as every function 
  /// in the Layer class assumes that a valid gisLayer is present.
  [Test]
  public void ShouldNotAllowConstructionWithANullGisLayer()
  {
  }
  • This may seem obvious, but this practice will protect the integrity of your tests from people who don't understand the reason behind the test in the first place. I've seen many tests get removed or modified that were perfectly fine, simply because the person didn't understand the assumptions that the test was verifying.
  • If the test is trivial or the method name is sufficiently descriptive, it can be permissible to leave the comment off.

5. Every test must always revert the state of any resource it touches

  • Use mocks where possible to avoid dealing with real resources.
  • Cleanup must be done at the test level. Tests must not have any reliance on order of execution.
查看更多
谁念西风独自凉
5楼-- · 2019-01-01 04:49

Often unit tests are based on mock object or mock data. I like to write three kind of unit tests:

  • "transient" unit tests: they create their own mock objects/data and test their function with it, but destroy everything and leave no trace (like no data in a test database)
  • "persistent" unit test: they test functions within your code creating objects/data that will be needed by more advanced function later on for their own unit test (avoiding for those advanced function to recreate every time their own set of mock objects/data)
  • "persistent-based" unit tests: unit tests using mock objects/data that are already there (because created in another unit test session) by the persistent unit tests.

The point is to avoid to replay everything in order to be able to test every functions.

  • I run the third kind very often because all mock objects/data are already there.
  • I run the second kind whenever my model change.
  • I run the first one to check the very basic functions once in a while, to check to basic regressions.
查看更多
裙下三千臣
6楼-- · 2019-01-01 04:49

I use a consistent test naming convention described by Roy Osherove's Unit Test Naming standards Each method in a given test case class has the following naming style MethodUnderTest_Scenario_ExpectedResult.

    The first test name section is the name of the method in the system under test.
    Next is the specific scenario that is being tested.
    Finally is the results of that scenario.

Each section uses Upper Camel Case and is delimited by a under score.

I have found this useful when I run the test the test are grouped by the name of the method under test. And have a convention allows other developers to understand the test intent.

I also append parameters to the Method name if the method under test have been overloaded.

查看更多
残风、尘缘若梦
7楼-- · 2019-01-01 04:51

Keep these goals in mind (adapted from the book xUnit Test Patterns by Meszaros)

  • Tests should reduce risk, not introduce it.
  • Tests should be easy to run.
  • Tests should be easy to maintain as the system evolves around them

Some things to make this easier:

  • Tests should only fail because of one reason.
  • Tests should only test one thing
  • Minimize test dependencies (no dependencies on databases, files, ui etc.)

Don't forget that you can do intergration testing with your xUnit framework too but keep intergration tests and unit tests separate

查看更多
登录 后发表回答