0

I have method something like this:

func (alert *Alert) CreateAlert(db *mgo.Database) error {
    return db.C("alerts").Insert(&alert)
}

How should I unit test this? If I just call this method for uni test, then I will have to create test DB to which the call is made. I somehow feel that this would be part of integration test as we are making a call to DB.

If I mock the db object, then it will never test the actual implementation.

Should I test this at all? as the major goal for writing unit test if the data is inserted to DB or not, and such functionality are already tested in the library itself, in my case mgo library.

Please share your thoughts on what would be the best approach for unit testing the above scenario.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Ankit Sahu
  • 387
  • 1
  • 3
  • 11
  • 2
    You would not *unit test* it. Unit tests must be conducted in isolation. – zerkms Dec 26 '17 at 10:14
  • @zerkms So this part of code will always remain uncovered when it comes to unit tests? It will only be covered when the integration tests are done, is it? – Ankit Sahu Dec 26 '17 at 10:16
  • @zerkms: It is quite possible to test such a function with a unit test. – Jonathan Hall Dec 26 '17 at 11:06
  • @Flimzy it's a good rule of thumb to not mock interfaces you don't own. If you mock `db` object there - your test's value would be close to 0. – zerkms Dec 26 '17 at 20:11
  • @zerkms: 1. I don't think there's any validity to that "rule" at all. 2. Not all mocks must happen at the interface level. – Jonathan Hall Dec 26 '17 at 22:19

1 Answers1

2

You would unit test it with a mock, so that the database isn't being called, but only your function is being tested.

There are many different ways to mock a database, so I won't get into details, but a unit-test for such a small function will also be small. All you'll really be testing is that:

  1. the mock receives the expected data, in the expected format (i.e. does it receive the &alert value, passed to its Insert() method?)
  2. the mock's return value (an error) is returned to the caller of the function

In particular, in a unit test of this function, you would not check that:

  • The SQL conforms to syntax expectations (your function doesn't control SQL, such a test would really be testing your data layer/ORM)
  • That the INSERT occurs as expected--this would be testing your database
  • That the caller of the function has appropriate database permissions (this is again testing your data layer and/or database)
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • Database part (mgo.Database) should be tested separately. Am I right? – Innokentiy Alaytsev Dec 26 '17 at 11:12
  • 1
    @InnokentiyAlaytsev: That should be tested by the `mgo` package. The purpose of a unit test is to test a specific unit--the unit in the question is the `CreateAlert` function, so only the functionality unique to that function should be unit-tested. – Jonathan Hall Dec 26 '17 at 11:16
  • Thank you @Flimzy for explaining what exactly needs to be tested here, made things clearer for me moving forward. – Ankit Sahu Dec 26 '17 at 11:28
  • "the mock receives the expected data, in the expected format" --- this would test the implementation details, that's a no-no-no thing for unit tests. – zerkms Dec 26 '17 at 20:14
  • @zerkms Not at all. You have misinterpreted my answer. In this case, the relevant "format" is just that the expected data type is sent to the expected method. In more complex cases, it may include validating that the data is in valid JSON or XML or whatever, or that the proper fields of a struct are set. Since all _this_ function does is pass an argument, unaltered, the "format" is minimal. – Jonathan Hall Dec 26 '17 at 22:22
  • @Flimzy any chance "but a unit-test for such a small function will also be small" --- to see it then? – zerkms Dec 26 '17 at 22:31