2

I have a utility function called connectToMongoDB() which connects to MongoDB. Basically, it creates a client for MongoDB and returns that.

I'm making a library and I'm thinking of unit testing the utility functions. The way my unit test would work is by calling the function, then doing CRUD operations on it and seeing if it works.

Is this a good idea, or does this count as doing the testing for the MongoDB package I am using?

For whatever it's worth, I'm using Go 1.17 and not in a main package (my library is not an executable on its own.)

DaCool1
  • 37
  • 3

4 Answers4

3

Why do you write unit tests? Because you want to find bugs with little effort and fix them easily, and/or because you want confidence that everything works the way it should or the way it is expected to work.

Unless you are 100% sure that this function will never fail (and you can never be 100% sure), you can do unit tests even for third party code. Moreover, lots of third party code has bad documentation. So you have an additional bit of documentation: You can tell your colleagues "if you want to know exactly what this function does, look at the unit tests, because it passes those". If someone asks "does this function do what I expect if I do X and I expect Y as the outcome", it's great if you can point them to a unit tests that does X and checks that the outcome is Y.

gnasher729
  • 42,090
  • 4
  • 59
  • 119
  • I think I'll write the unit tests in the event that a new developer joins the project, or a breaking change is released. – DaCool1 Feb 16 '22 at 01:45
1

I'm making a library and I'm thinking of unit testing the utility functions. The way my unit test would work is by calling the function, then doing CRUD operations on it and seeing if it works.

Is this a good idea, or does this count as doing the testing for the MongoDB package I am using?

If this would test the utility functions in your library (rather than an imported library), then it's a fine idea. Finding problems there before running larger tests would save debugging time.

As a matter of perspective, I'd call this a configuration test, not a unit test since it'd mainly detect configuration problems with the MongoDB server and the network. It's neither a "small test" nor a "fast test" since it depends on a separate server. (The terms matters for communication, to keep each type of test good at its particular purpose, and to decide when to run each test.)

If you want to isolate a test of your library from MongoDB configuration and network problems, a good technique is to mock out its access to the MongoDB server or else to test against an in-memory MongoDB server. This also speeds up the test so it becomes a "fast test" that's fine to run every time on every code change.

If you're asking about testing the MongoDB server itself, then I'd call that an acceptance test. The purpose of acceptance testing is to test requirements on MongoDB that your project depends on, e.g. to catch problems for your project introduced by new releases of MongoDB. Server changes aren't always compatible, or perhaps your project depended on details that it shouldn't. This is a good place for tests of MongoDB semantics that caused past problems for your project.

Jerry101
  • 5,367
  • 1
  • 15
  • 19
  • Thanks for the answer! I think I might make a small function that spins up a local MongoDB database, so that connection times reduce and the tests run faster. – DaCool1 Feb 18 '22 at 02:36
0

As a general rule, do not write tests verifying the behavior of external code. I would never write a test that asserts string.Format("green {0}", "apple") returns "green apple". This is something the vendor or provider of that external code should verify. Keep your tests focused on verifying your behavior and configuration as it integrates with that external code.

For example, say I have a function named string makeFruitGreen(string fruit). Internally it might call string.Format("green {0}", fruit), but writing a test that asserts makeFruitGreen("apple") returns "green apple" is a useful test, because it verifies the behavior of making a fruit green. Calling an external/3rd party function is an implementation detail. If makeFruitGreen("apple") starts returning "red apple" I would want a failing test — even if, internally, the broken function is still calling string.Format. The call to string.Format works. There is a bug in makeFruitGreen that passes "red {0}" instead of "green {0}" in the call to that external function.

More importantly, as it relates to connecting to MongoDB, what you are proposing is not a unit test. Since the test is using a resource outside the current call stack, it is a form of integration testing. This is still a valuable test, but again, do not test that connectToMongoDB() works. Instead, test a higher level function your team wrote that internally calls connectToMongoDB(). Tests like this verify configuration and integration logic in your code, rather than the logic in the external function that connects to a data source.

Greg Burghardt
  • 34,276
  • 8
  • 63
  • 114
  • Okay, would I make an artificial method for this? Like, would I make a function that would just perform CRUD and see if it works? Or would I test an actual method that is important to my library? – DaCool1 Feb 18 '22 at 02:44
  • @DaCool1: An actual method that is important to your library. And if your code is peppered with calls to `connectToMongoDB()`, then I would advise refactoring your code so data access is in its own module, which can be tested like this. – Greg Burghardt Feb 18 '22 at 12:55
  • I'm already testing the methods that use `connectToMongoDB()`. I'm just hoping to catch any breaking changes and/or important changes to their API without a whole debugging session. `connectToMongoDB` is used a LOT in my codebase, pretty much in every method/function. – DaCool1 Feb 18 '22 at 17:32
0

My two cents:

With a very well defined interface you can mock mongoDB. However you should mock it right. It is a powerful technique, specially to test corner cases such as specific errors, etc.

Try to write integration tests that can connect to a real database. Use flags for this. This is another layer of testing and you need to be sure about the correct setup of each test.

Only integration tests does b