Testing D database calls code for regression
aberba
karabutaworld at gmail.com
Mon Mar 19 18:45:49 UTC 2018
On Monday, 19 March 2018 at 00:56:26 UTC, H. S. Teoh wrote:
> On Sun, Mar 18, 2018 at 07:51:18PM +0000, aberba via
> Digitalmars-d-learn wrote:
>> On Friday, 16 March 2018 at 21:15:33 UTC, H. S. Teoh wrote:
>> > On Fri, Mar 16, 2018 at 08:17:49PM +0000, aberba via
>> > Digitalmars-d-learn wrote:
>> > > [...]
>> >
>> > The usual way I do this is to decouple the code from the
>> > real database backend by templatizing the database driver.
>> > Then in my unittest I can instantiate the template with a
>> > mock database driver that only implements the bare minimum
>> > to run the test.
>> >
>> > [...]
>>
>> Mocking a fake database can also be huge pain. Especially when
>> something like transactions and prepared statements are
>> involved.
>
> It depends on what your test is looking for. The idea is that
> the mock database only implements a (small!) subset of a real
> database, basically just enough for the test to run, and
> nothing more. Of course, sometimes it may not be easy to do
> this, if the code being tested is very complex.
>
>
>> Imagine testing your mock for introduced by future extension.
>
> If you find yourself needing to test your mock database, then
> you're doing it wrong. :-D It's supposed to be helping you
> test your code, not to create more code that itself needs to be
> tested!
>
> Basically, this kind of testing imposes certain requirements on
> the way you write your code. Certain kinds of code are easier
> to test than others. For example, imagine trying to test a
> complex I/O pipeline implemented as nested loops. It's
> basically impossible to test it except as a blackbox testing
> (certain input sets must produce certain output sets). It's
> usually impractical for the test to target specific code paths
> nested deep inside a nested loop. The only thing you can do is
> to hope and pray that your blackbox tests cover enough of the
> code paths to ensure things are correct. But you're likely to
> miss certain exceptional cases.
>
> But if said I/O pipeline is implemented as series of range
> compositions, for example, then it becomes very easy to test
> each component of the range composition. Each component is
> decoupled from the others, so it's easy for the unittest to
> check all code paths. Then it's much easier to have the
> confidence that the composed pipeline itself is correct.
>
> I/O pipelines are an easy example, but understandably, in
> real-world code things are rarely that clean. So you'll have
> to find a way of designing your database code such that it's
> more easily testable. Otherwise, it's going to be a challenge
The thing about functional programming where functions are
decoupled/testable doesn't seem to apply to database call code. I
guess its because databases introduces a different
state...another point of failure.
> no matter what. No matter what you do, testing a function made
> of loops nested 5 levels deep is going to be very hard.
> Similarly, if your database code has very complex
> interdependencies, then it's going to be hard to test no matter
> how you try.
My code logic is a mix of file uploads which leads to saving file
info into db. And some general queries... my worry has been
adding a feature which might cause a regression in another rearly
executed code...its feels like I have to test all features/rest
calls after every major change. Don't know how others do
this...when there's some tight coupling involved.
>
> Anyway, on the more practical side of things, depending on what
> your test is trying to do, a mock database could be as simple
> as:
>
> struct MockDb {
> string prebakedResponse;
> auto query(string sql) {
> if (sql == "SELECT * FROM data")
> return prebakedResponse;
> else if (sql == "UPDATE * SET ... ")
> prebakedResponse = ...
> else
> assert(0, "Time to rewrite your unittest :-P");
> }
> }
>
> I.e., you literally only need to implement what the test case
> will actually invoke. Anything that isn't strictly required is
> fair game to just outright ignore.
>
> Also, keep in mind that MockDb can be a completely different
> thing per unittest. Trying to use the same mock DB for all
> unittests will just end up with writing your own database
> engine, which kinda defeats the purpose. :-P But the ability
> to do this depends on how decoupled the code is. Code with
> complex interdependencies will generally give you a much harder
> time than more modular, decoupled code.
>
>
> T
More information about the Digitalmars-d-learn
mailing list