package controllers;
import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.*;
import static play.test.Helpers.contentAsString;
import static play.test.Helpers.running;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import play.Configuration;
import play.GlobalSettings;
import play.db.jpa.JPA;
import play.libs.F;
import play.mvc.Result;
import play.test.FakeApplication;
import play.test.Helpers;
import play.test.WithApplication;
import settings.TestSettings;
public class CategoryControllerTest {
@Test
public void checkProductsList() {
/**
* FakeApplication is a kind of mocked application context. Without it we won't able to run controllers. By running them
* by simple execution (Result result = CategoryController.showOne(1, 1)) you'll receive RuntimeExceptions of following
* type:
* <pre>
* java.lang.RuntimeException: There is no started application
* </pre>
*
* If one class extends WithApplication, we don't need to create FakeApplication manually. This object
* is automatically created by provideFakeApplication() method of WithApplication class and is accessible
* as a protected field called app.
*
* We don't do that because of connection problems to test database. If we
* use manually made FakeApplication, the test case is able to connect to play_store_test. But if we use
* app field and extends the class with WithApplication, the test can't connect to test database.
*/
FakeApplication fakeApp = Helpers.fakeApplication();
final Map<String, String> threads = new HashMap<String, String>();
threads.put("current", Thread.currentThread().getName());
running(fakeApp, new Runnable() {
@Override
public void run() {
/**
* We need to use once again a JPA.withTransaction to avoid following RuntimeException:
* <pre>
* java.lang.RuntimeException: No EntityManager bound to this thread. Try wrapping
* this call in JPA.withTransaction, or ensure that the HTTP context is setup on this thread.
* </pre>
*/
try {
JPA.withTransaction(new F.Function0<Void>() {
@Override
public Void apply() throws Throwable {
Result result = CategoryController.showOne(1, 1);
String stringResult = contentAsString(result);
// check if bread and butter are present as products
String[] expectedProducts = {"<a href=\"/categories/1/products/bread_1\">bread</a>",
"<a href=\"/categories/1/products/butter_2\">butter</a>"};
for (String expectedProduct : expectedProducts) {
assertTrue("Response should contain "+expectedProduct+" but it doesn't", stringResult.contains(expectedProduct));
}
threads.put("runnable", Thread.currentThread().getName());
return null;
}
});
} catch (Throwable e) {
e.printStackTrace();
}
}
});
// Even if the test case is written as Runnable anonymous class, it will be executed in the same thread as
// the main thread. So they won't be the concurrency testing issues and synchronization problems between
// the main test thread and other testing threads. Usually they need to be synchronized manually with
// CountDownLatch, CyclicBarrier or another technique.
// You can learn more about synchronization in multi-threading environment through this article:
// <a href="http://www.waitingforcode.com/java/java-concurrency/tests-inmulti-threading-environment-with-junit/read">Tests in multi-threading environment with JUnit</a>
assertTrue("Test case within running() should be executed in the same thread as the main ("+threads.get("current")+") "+
"but it wasn't ("+threads.get("runnable")+")", threads.get("current").equals(threads.get("runnable")));
}
}