8

I have a bug that manifest himself only when database is slow. It applies to even simplest database operations (select, etc).

I would like to create test, where I force my database to be slow. How to do that?
I use Spring Boot, Spring Data, Hibernate, MariaDB.

Ideally, I want the 'slow database' part to be completely contained in the test code, in my java application. That way, test will be completely automated and self-contained.

I want to slow down database access only for one test (not globally, for all access).

I was proposed to introduce database trigger (BEFORE SELECT) with sleep

But this is not flexible, because it slows down every access, not access just for one test.

Bartosz Bilicki
  • 12,599
  • 13
  • 71
  • 113
  • 3
    The easy answer is to write a test repository class that has a Thread.sleep embedded in it. – duffymo Sep 07 '16 at 13:00
  • @duffymo using `Thread.sleep` seems like a bad idea, almost like purposely slowing down but not knowing how much to slow down. – px06 Sep 07 '16 at 13:04
  • 2
    Bad idea? It's a test - that's the whole idea as I understand it. You could make it a random value over a range if you'd like. The point is that a degree of slowness that's associated with failure is known. – duffymo Sep 07 '16 at 13:21
  • Thread.sleep for test only is good enough for me. Simple and does what's needed. – Bartosz Bilicki Sep 07 '16 at 13:30
  • Some of the answers to [this question](http://stackoverflow.com/questions/1094760/network-tools-that-simulate-slow-network-connection) might be of interest. – Gord Thompson Sep 07 '16 at 13:55
  • "It's slow" probably isn't the _actual_ cause. It's something like a timeout, or failed transaction due to a conflict, etc. I would try to find that problem and test for it, either instead of or in addition to the time -based test. – yshavit Sep 07 '16 at 14:18
  • right. the root cause of my problem is exactly 'r failed transaction due to a conflict' but it manifest itself when database is slow. – Bartosz Bilicki Sep 07 '16 at 14:43
  • In that case, I would target that case, not the slowness; whether you do it via mocks, or an actual database connection with multiple threads and some CountDownLatches or something to coordinate them, you should be able to come up with a test that's both faster and more reliable than one that depends on sleeps. – yshavit Sep 07 '16 at 16:46

4 Answers4

13

I see four possible solutions for this problem.

  1. You don't have to create slow database, you can create slow connection to the database. If you run database on a different (Virtual) machine, there are systems that help simulating shitty internet connections by delaying network responses randomly.

  2. You can use sleep(10) function that is provided by your database, this would require "injecting" it into SQL query or override method for the purpose of test and replace SELECT with SELECT SLEEP(10).

  3. Simulate stress-test on the database with mysqlslap if you use mysql.

  4. Another solution, a bit stupid tho, you can use spring-aop and attach a delay aspect before and after the DAO method execution with random small sleep. This way you have control over it, don't have to modify existing code and let spring make the job of doing the delay without integration into real-system. Not that stupid after all. This one is quite flexible and I think I would go with it. Easiest to setup.

If it's stupid, but it works, it's not stupid.

agilob
  • 6,082
  • 3
  • 33
  • 49
  • I like spring-aop solution most. It is easy to do this just for the test. Other solutions are more complex, have more moving parts that require manual setup. I do not mind writing a few lines of code- if my 'slow database' test will be fully automated. – Bartosz Bilicki Sep 07 '16 at 13:17
  • 1
    @BartoszBilicki Depending what do you mean by one test, I think solution 4 is easy to setup and flexible. If your test is on selemium or tests something end-to-end it might not be the best, but definitely the easiest. – agilob Sep 07 '16 at 13:18
  • 1
    Right, solution 4 is suitable for junit test, that mocks part of the application. Is it not applicable for end-to-end test. – Bartosz Bilicki Sep 07 '16 at 13:19
10

I had a similar need when developing on a SQL Server DB.

To simulate a slow query you can use (but this is specific to SQL Server):

select * from TABLE
WAITFOR DELAY '00:00:45'--to simulate 45 seconds of delay
UnDiUdin
  • 14,924
  • 39
  • 151
  • 249
1

If you want to write a Spring Boot Test, maybe you can use the @SpyBean annotation

   @SpyBean
   SomeBeanCallingTheDatabase someBeanCallingTheDatabase;

   //...
   // in the test method

   doAnswer(answer-> {
                Thread.sleep(300L); //any value here
                return answer.callRealMethod();
            })
    .when(someBeanCallingTheDatabase)
                .find(any());

   // call the service using the bean above
Mihaita Tinta
  • 219
  • 2
  • 6
-2

The easy answer is to write a test repository class that has a Thread.sleep embedded in it.

credit: this answer was provided by https://stackoverflow.com/users/37213/duffymo in the comment.

Community
  • 1
  • 1
Bartosz Bilicki
  • 12,599
  • 13
  • 71
  • 113