0

I have a method which starts generating some report in another thread while the main thread returns a link to a google folder where created report should be uploaded. After report was created, it inserts a record with some information in the database.

public Link startReportCreation(ReportRequest reportRequest) {
    Link link = /** some logic **/;
    taskExecutor.execute(() -> {
        /** report creation logic **/
    });
    return link;

So what is the best way to test the info of the inserted record without modifying the startReportCreation method?


Update

Currently I have while (taskExecutor.getActiveCount() != 0); kind of lock, which indicates that taskExecutor ended its execution and I can check the database. But I think there is a better approach.


Btw sry for misleading, that is not a unit test, it's just an executor to manually test methods on real data.


Solved

So I've managed to refactor my startReportCreation method and instead of simple taskExecutor I used CompletableFuture, so now it's looks like this:

public CompletableFuture<Link> startReportCreation(ReportRequest reportRequest) {
    /** some logic **/
    return CompletableFuture.supplyAsync(() -> {
        Link link = /** some logic **/;
        return link;
    }, taskExecutor);
}

So in production code I use CompletableFuture.getNow() method and in tests I use CompletableFuture.get() to wait for the report creation.

Praytic
  • 1,771
  • 4
  • 21
  • 41

1 Answers1

0

First of all remember the FIRST principles of unit testing. F: Fast I: Independent R: Repeatable S: Small T: Timely

Here you are a linik to review them in detail: https://github.com/ghsukumar/SFDC_Best_Practices/wiki/F.I.R.S.T-Principles-of-Unit-Testing

To achieve what you need, you must prepare the test in this way:

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertTrue;

public class ReportGeneratorTest {

    //This is executed before each @Test, generally is used for prepare the ambient, instantiate services, start servers and so on.
    @Before
    public void setUp() throws IOException {
        report = MyReportService.createReport();
    }

    //This is executed after each @Test generally this used for tear down your servers or data bases, or delete all the records inserted
    @After
    public void tearDown() {
        MyReportService.deleteById(10);
    }

    @Test
    public void verifyInsertion() throws Exception {
        //Here you can verify that the record of your serive or logic it's ok
        assertTrue(MyReportService.getLastId() > 10); //Or whatever
    }
}

EDIT:

From the documentation of concurrent unit: https://github.com/jhalterman/concurrentunit/blob/master/src/test/java/net/jodah/concurrentunit/WaiterTest.java You could create a Thread and wait for it.

@Test
public class WaiterTest {
  @Test
  public void shouldSupportMultipleThreads() throws Throwable {
    final Waiter waiter = new Waiter();

    for (int i = 0; i < 5; i++)
      new Thread(new Runnable() {
        public void run() {
          waiter.assertTrue(true);
          waiter.resume();
        }
      }).start();

    waiter.await(0);
  }
sirandy
  • 1,834
  • 5
  • 27
  • 32
  • This won't work on my example, because `createReport()` method will start report creation in another thread and `verifyInsertion` will not see any changes in the database yet. – Praytic Mar 29 '17 at 19:10
  • I see, well maybe this approach could help you: http://stackoverflow.com/questions/5336251/how-do-i-write-a-junit-test-case-to-test-threads-and-events – sirandy Mar 29 '17 at 20:50
  • But I don't want to insert those `Waiters` in my code just to test it (and I don't see any case where someone will use it). – Praytic Mar 29 '17 at 21:16
  • Yeah, I guess my requirements are too high, it seems I need to restructure the code in order to properly test it. Anyway, thanks for that link, really helpful with that `CompletionService`. – Praytic Mar 29 '17 at 21:46