GithubHelp home page GithubHelp logo

darrmirr / dbchange Goto Github PK

View Code? Open in Web Editor NEW
3.0 1.0 0.0 171 KB

Easy and declarative way to execute sql queries in JUnit tests.

Home Page: https://github.com/DarrMirr/dbchange

License: MIT License

Kotlin 3.61% Java 96.39%
database java junit junit5 junit5-extension sql

dbchange's Introduction


Easy and declarative way to execute sql queries in JUnit tests.

Project goals

  1. Provide rich API to code sql queries that are executed in tests written on JUnit 5.
  2. Simplify sql queries maintaining in code base.
  3. Provide library independent of various frameworks (Uses only standard Java library and Junit 5 compile dependency)

Core concept

There are three annotations:

  1. DbChange
  2. DbChangeOnce
  3. SqlExecutorGetter

DbChange

Provide meta information about RDBMS changes before/after EACH test execution in class.

DbChangeOnce

Provide meta information about RDBMS changes before/after ALL tests execution in class.

SqlExecutorGetter

Set default sql executor for all tests in class. Value in this annotation should be the name of public method in test class that returns instance of DefaultSqlExecutor.

Annotations position in code:

@ExtendWith(DbChangeExtension.class)
@DbChangeOnce
@SqlExecutorGetter
public class DbChangeUsageTest {
    
    @Test
    @DbChange
    void test() {
    }
}

How to plug library into project

Gradle

  1. Open to edit build.gradle.kts (or build.gradle for groovy)
  2. Add Dbchange dependency to project
dependencies {
    testImplementation("io.github.darrmirr:dbchange:1.0.1")
}

Maven

  1. Open to edit your project pom.xml
  2. Add Dbchange dependency to dependecies section
    <dependency>
        <groupId>io.github.darrmirr</groupId>
        <artifactId>dbchange</artifactId>
        <version>1.0.1</version>
        <scope>test</scope>
    </dependency>

How to use extension

  1. (mandatory) Put @ExtendWith(DbChangeExtension.class) on test class.
  2. (mandatory) Create public method in test class that returns instance of DefaultSqlExecutor.
  3. (optional) Put @DbChangeOnce on test class
  4. (optional) Put @SqlExecutorGetter on test class
  5. (optional) Put @DbChange on test method

Points to notice:

  • If there are no annotations @DbChangeOnce or @DbChange in test class then Dbchange library does nothing during test execution.
  • If @SqlExecutorGetter is not present on test class then it is mandatory to set value sqlExecutorGetter in each @DbChangeOnce and @DbChange annotation.
  • If you use @DbChangeOnce in test then you have to initialize instance of DataSource class at test class constructor or in static context (for example, using JUnit annotation @BeforeAll)

Simple example:

@ExtendWith(DbChangeExtension.class)
@DbChangeOnce(sqlQueryFiles = "sql/database_init.sql")
@DbChangeOnce(sqlQueryFiles = "sql/database_destroy.sql", executionPhase = ExecutionPhase.AFTER_ALL)
@SqlExecutorGetter("defaultSqlExecutor")
public class DbChangeUsageTest {
    private DataSource dataSource;
    
    public DbChangeUsageTest() {
        dataSource = // code to create instance of dataSource 
    }

    public SqlExecutor defaultSqlExecutor() {
        return new DefaultSqlExecutor(dataSource);
    }

    @Test
    @DbChange(changeSet = InsertEmployee6Chained.class )
    @DbChange(changeSet = DeleteEmployee6Chained.class , executionPhase = DbChange.ExecutionPhase.AFTER_TEST)
    void changeSetChained() {
        /* code omitted */
    }
}

Sql queries suppliers

There are following sql queries suppliers:

  • statements
    @Test
    @DbChange(statements = {
            "insert into department(id, name) values (14, 'dep14');",
            "insert into occupation(id, name) values (8, 'occ8');",
            "insert into employee(id, department_id, occupation_id, first_name, last_name) values (10, 14, 8, 'Ivan', 'Ivanov')"
    })
    @DbChange(statements = {
            "delete from employee where id = 10;",
            "delete from occupation where id = 8;",
            "delete from department where id = 14;"
    }, executionPhase = DbChange.ExecutionPhase.AFTER_TEST)
    void statements() { /* code omited */ }
  • sql query files
    @Test
    @DbChange(sqlQueryFiles = {"sql/sqlqueryfiles/sqlQueryFilesTest1_init.sql", "sql/sqlqueryfiles/sqlQueryFilesTest2_init.sql"})
    @DbChange(sqlQueryFiles = "sql/sqlqueryfiles/sqlQueryFilesTest_destroy.sql", executionPhase = DbChange.ExecutionPhase.AFTER_TEST)
    void sqlQueryFiles() { /* code omited */ }
  • sql query getter
    @Test
    @DbChange(sqlQueryGetter = "testSqlQueryGetterInit")
    @DbChange(sqlQueryGetter = "testSqlQueryGetterDestroy", executionPhase = DbChange.ExecutionPhase.AFTER_TEST)
    void sqlQueryGetter() { /* code omited */ }

    public SqlQueryGetter testSqlQueryGetterInit() { /* code omited */ }

    public SqlQueryGetter testSqlQueryGetterDestroy() { /* code omited */ }
  • changeset
    @Test
    @DbChange(changeSet = InsertEmployee6Chained.class )
    @DbChange(changeSet = DeleteEmployee6Chained.class , executionPhase = DbChange.ExecutionPhase.AFTER_TEST)
    void changeSetChained() { /* code omited */ }
  • @MethodSource (only for JUnit parameterized test)
    @ParameterizedTest
    @MethodSource("sourceSqlQueryGetterParameterized")
    void sqlQueryGetterParameterized(List<DbChangeMeta> dbChangeMetas, List<Department> expectedDepartments) { /* code omited */ }

    public static Stream<Arguments> sourceSqlQueryGetterParameterized() { /* code omited */ }

Notice:

  • all sql queries suppliers (except @MethodSource) are supported by @DbChange and @DbChangeOnce annotations.

See usage example in com.github.darrmirr.dbchange.component.DbChangeUsageTest class.

Read article on medium.com for more details

Minimum requirements:

Runtime:

  • JRE 8
  • JUnit 5.9+ in classpath

Development:

  • JDK 8
  • Gradle 7

Articles:

dbchange's People

Contributors

darrmirr avatar

Stargazers

 avatar  avatar

Watchers

 avatar

dbchange's Issues

Unable to runt the script file

I am using dbchange version 1.0.1 and trying to run the script using the following code:

@ExtendWith(DbChangeExtension.class)
@DbChangeOnce(sqlQueryFiles = "resources/db_init.sql", executionPhase = ExecutionPhase.BEFORE_ALL)
@SqlExecutorGetter("defaultSqlExecutor")
class EventTableTest {

	private static SqlConnection conn;

	public SqlExecutor defaultSqlExecutor() {
		PGSimpleDataSource ds = new PGSimpleDataSource();
		ds.setServerName(conn.getHost());
		ds.setUser(conn.getUser());
		ds.setPassword(conn.getPassword());
		ds.setPortNumber(conn.getPort());

		return new DefaultSqlExecutor(ds);
	}

}

Getting the following error:

java.lang.IllegalStateException: org.postgresql.util.PSQLException: No value specified for parameter 1.
	at com.github.darrmirr.dbchange.sql.executor.DefaultSqlExecutor.execute(DefaultSqlExecutor.java:56)
	at com.github.darrmirr.dbchange.DbChangeExtension.handle(DbChangeExtension.java:110)
	at com.github.darrmirr.dbchange.DbChangeExtension.lambda$beforeAll$1(DbChangeExtension.java:57)
	at com.github.darrmirr.dbchange.DbChangeExtension.postProcessTestInstance(DbChangeExtension.java:129)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$10(ClassBasedTestDescriptor.java:377)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:382)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$11(ClassBasedTestDescriptor.java:377)
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1382)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)
	at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:743)
	at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:742)
	at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:376)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$instantiateAndPostProcessTestInstance$6(ClassBasedTestDescriptor.java:289)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:288)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$4(ClassBasedTestDescriptor.java:278)
	at java.util.Optional.orElseGet(Optional.java:267)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$5(ClassBasedTestDescriptor.java:277)
	at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:105)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:104)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:68)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$2(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:90)
	at java.util.ArrayList.forEach(ArrayList.java:1257)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.util.ArrayList.forEach(ArrayList.java:1257)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:95)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:91)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:60)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: org.postgresql.util.PSQLException: No value specified for parameter 1.
	at org.postgresql.core.v3.SimpleParameterList.checkAllParametersSet(SimpleParameterList.java:257)
	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:292)
	at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
	at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
	at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:143)
	at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:120)
	at com.github.darrmirr.dbchange.sql.executor.DefaultSqlExecutor.execute(DefaultSqlExecutor.java:53)
	... 70 more

here is the resources/db_init.sql file:

CREATE SEQUENCE IF NOT EXISTS events_id_seq;
DROP TABLE IF EXISTS public.events CASCADE;

CREATE TABLE events
(
    id bigint NOT NULL DEFAULT nextval('events_id_seq'::regclass),
    eventtype integer,
	eventlevel integer,
	eventmessage character varying(500) COLLATE pg_catalog."default",
	eventtime time without time zone,
    "timestamp" bigint,
    appid character varying COLLATE pg_catalog."default",
    CONSTRAINT events_pkey PRIMARY KEY (id)
);

Is there any mistake or do i missing something?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.