I have two test classes: PostIT and UserIT. Test cases in both classes make requests against the same server (Spark) and are dependent. I need the tests being executed like this:
Start server
Run PostIT tests
Stop server
Start server
Run UserIT tests
Stop server
Now, I have this:
class PostIT {
#Before
fun initialise() {
startServer()
}
#Test
fun test1() {
}
//more test cases
}
class UserIT {
#Before
fun initialise() {
startServer()
}
#Test
fun test1() {
}
//more test cases
}
Both classes are executed in parallel so I have some errors due to the dependencies between test cases.
How can I solve this?
Related
In JUnit 4 you could use a Rule to wrap a test so that you could execute code both before and after a test had run. In most cases this could be accomplished with an #Before and #After method or an ExternalResource rule. However some control flow constructs (like try-with-resources) cannot be split into two methods. In most cases, there are alternatives to these constructs which allow you to split them into two methods. For example, with try-with-resources, you can manually acquire and close a resource instead of using a try block.
The specific problem that I have run into is that the database library I use, jOOQ, only has transaction methods that take a callback. (See https://www.jooq.org/doc/latest/manual/sql-execution/transaction-management/) You cannot call something like:
context.startTransaction()
doStuff()
context.commit() // Or rollback()
In JUnit4 this is ok because you can write a rule like so (in Kotlin, but the equivalent works in Java):
class TransactionRule(private val dbSessionManager: DBSessionManager) : TestRule {
override fun apply(base: Statement, description: Description): Statement {
return object : Statement() {
override fun evaluate() {
dbSessionManager.transaction {
base.evaluate()
}
}
}
}
}
Is there anything similar in JUnit 5?
You can write an InvocationInterceptor in place of the JUnit4 rule:
public class TransactionInvocationInterceptor implements InvocationInterceptor {
#Override
public void interceptTestMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) throws Throwable {
runInTransaction(() -> {
try {
invocation.proceed();
} catch (Throwable t) {
throw new RuntimeException(t);
}
});
}
}
#ExtendWith(TransactionInvocationInterceptor.class)
class InvocationInterceptorTest {
#Test
void test() {
…
}
}
One difference is that interceptTestMethod only wraps the test method, not other lifecycle methods such as beforeEach. It's possible to intercept the other lifecycle methods individually with the other methods in InvocationInterceptor, but not multiple at a time (for example, if you want to call both beforeEach and the test method in one transaction).
From what I understand you can't use the JUnit 5 test lifecycle callbacks as they would require you to follow the doStuff route with context calls Before/After that you indicate won't work.
Would using JUnit 5 Dynamic Tests instead work?
This provides for test factories consisting of collections of dynamic test with a name and an executable (lambda). You could then do something like this:
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import org.junit.jupiter.api.function.Executable;
#TestFactory
Collection<DynamicTest> transactionTestCollection() {
return Arrays.asList(
dbTest("1st dynamic test", () -> assertTrue(true)),
dbTest("2nd dynamic test", () -> assertEquals(4, 2 * 2))
);
}
private DynamicTest dbTest(String name, Executable tst) {
return dynamicTest(name, () -> dbSessionManager.transaction(tst));
}
Student here. In JUnit 5, what is the best way to implement conditional test execution based on whether another test succeeded or failed? I presume it would involve ExecutionCondition, but I am unsure how to proceed. Is there a way to do this without having to add my own state to the test class?
To note, I am aware of dependent assertions, but I have multiple nested tests that represent distinct substates, and so I would like a way to do this at the test level itself.
Example:
#Test
void testFooBarPrecondition() { ... }
// only execute if testFooBarPrecondition succeeds
#Nested
class FooCase { ... }
// only execute if testFooBarPrecondition succeeds
#Nested
class BarCase { ... }
#Nested tests give the test writer more capabilities to express the
relationship among several groups of tests. Such nested tests make use
of Java’s nested classes and facilitate hierarchical thinking about
the test structure. Here’s an elaborate example, both as source code
and as a screenshot of the execution within an IDE.
As stated from JUnit 5 documentation, #Nested is use for convenient display in your IDE. I would rather use Assumptions for your preconditions inside a Depentent Assertions.
assertAll(
() -> assertAll(
() -> assumeTrue(Boolean.FALSE)
),
() -> assertAll(
() -> assertEquals(10, 4 + 6)
)
);
You can fix the problem by extracting common precondition logic in a #BeforeEach/#BeforeAll setup method, then use assumptions, which was developed exactly for the purpose of condition test execution. Some sample code:
class SomeTest {
#Nested
class NestedOne {
#BeforeEach
void setUp() {
boolean preconditionsMet = false;
//precondition code goes here
assumeTrue(preconditionsMet);
}
#Test // not executed when precodition is not met
void aTestMethod() {}
}
#Nested
class NestedTwo {
#Test // executed
void anotherTestMethod() { }
}
}
I am trying to use DynamoDbLocal server for unit test cases.
And came up with two options,
Either define a junit class rule which starts local server before class and stops it after class. So essentially it will start and stop server for each unit test class.
public class MyDynamoDbLocalServerRule extends ExternalResource {
#Override
protected void before() throws Throwable {
myInMemoryDynamoDbServer.start();
}
#Override
protected void after() throws Throwable{
inMemoryDynamoDbServer.stop();
}
OR
Singleton instance :
public static DynamoDBProxyServerContainer createInstance(final int portToListenIn) {
if (dynamoLocal == null) {
synchronized (DynamoDBProxyServerContainer.class) {
if (dynamoLocal == null) {
dynamoLocal = new DynamoDBProxyServerContainer(portToListenIn);
}
}
}
return dynamoLocal;
}
private DynamoDBProxyServerContainer(final int portToListenIn) {
this.startServer(portToListenIn);
getRuntime().addShutdownHook(new Thread(() -> stopServer()));
}
Which one would you recommend and do you have better of doing this ? Please note i should be able to use it with Guice dependency injection framework.
I would recommend Singleton approach as creating the database instance for each test case will be a time consuming option. Also, if you have many test cases, the unit testing is likely to take more time to complete. If you have continuous integration, the build and unit test would take more time.
As the unit tests run in sequential manner, you don't need separate instance for each test case.
In the scenario below, I expect that the assertion failure in the step should make the test fail. What I am seeing is that the test continues and since a later assertion in the #Test method fails, the wrong exception is being reported, making it hard to debug.
Is there anyway I can get the test to stop when there is an assertion failure in a #Step?
#Test
public void test() {
....
steps.step1();
System.out.println("test should not reach here");
assertTrue(false);
}
#Step
public void step1() {
assertTrue(false);
}
Tried running the tests from my IDE and maven. (using ThucydidesRunner)
try to check this: http://thucydides.info/docs/thucydides/_creating_a_new_thucydides_project.html
in short words, in steps:
import net.thucydides.core.annotations.Step;
import static org.fest.assertions.Assertions.assertThat;
import static org.hamcrest.Matchers.is;
public class EndUserSteps extends Scenario Steps {
#Step
public void someStep() {
assertThat(true, is(false));
}
}
It turns out the tests don't stop, here is the reply I got from the creators of Thucydides:
"The test can't stop immediately, or it would be impossible to know what steps were not executed, so, yes, this is by design. They do record the first assertion error and then run the steps in "dry-run" mode (no WebDriver calls are made), but that's about the most it can guarantee."
In my webdriver script I have the three methods
setup, test and tearDown
following the junit convention.
In the test method I have few asserts like this
#Test
public void testStudentHome() throws Exception {
String classCode = "I6OWW";
Utilities.studentSignin(driver, baseUrl);
assertEquals(true, sth.openNotification());
assertEquals("My Scores", sth.myScores(true));
}
The sth is the PageObject on which I am performing the tests and that I have created in the setup method.
I am calling all these three methods from a main method like this:
public static void main(String[] args) {
StudentHomeTest sht = new StudentHomeTest();
try {
sht.setup();
sht.testStudentHome();
sht.tearDown();
} catch (Exception ex) {
Logger.getLogger(StudentHomeTest.class.getName()).log(Level.SEVERE, null, ex);
sht.tearDown();
}
}
Now while running the test if some assertion fails the test method should (this is what I expect) throw an exception and the main method should call the tearDown method. But this does not happen. and the browser window continues to stay there.
I am using the netbeans ide for running the test.
following the junit convention
If you follow the jUnit convention, then you will know that teardown methods belong in the #After method as this method will always run after your tests.
create a new method with the #After jUnit annotation.
#After
public void tearDown() {
sht.tearDown();
}
Edit
You know what, I believe that you are running into a classic issue of assertEquals in jUnit.
Stolen from this answer...:
JUnit calls the .equals() method to determine equality in the method assertEquals(Object o1, Object o2).
So, you are definitely safe using assertEquals(string1, string2). (Because Strings are Objects)
--
Instead of using assertEquals on these calls, use assertTrue() instead.
assertTrue(sth.openNotification());
assertTrue("My Scores".equals(sth.myScores(true)));
AssertionError doesn't extend Exception - it's a Throwable.
But in any case, you should have
try {
sht.setup();
sht.testStudentHome();
} finally {
sht.tearDown();
}
No need for a catch block. main can throw Exception.