Add annotation @ExpectMaxUpdatedColumn#2
Conversation
|
Many thanks for your contribution! With the current implementation, we find that the following tests don't fail but they should. In these cases, the update queries don't contain bind parameters. @Test
@ExpectMaxUpdatedColumn(1)
public void execute_update_with_two_columns_updated() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
String sql = "UPDATE book SET isbn ='12EEE', title = 'Book title'";
Query nativeQuery = em.createNativeQuery(sql);
nativeQuery.executeUpdate();
em.getTransaction().commit();
} @Test
@ExpectMaxUpdatedColumn(1)
public void execute_update_with_two_columns_updated() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
String sql = "UPDATE book SET isbn ='12,EEE', title = 'Book title'";
Query nativeQuery = em.createNativeQuery(sql);
nativeQuery.executeUpdate();
em.getTransaction().commit();
} @Test
@ExpectMaxUpdatedColumn(1)
public void execute_update_with_two_columns_updated() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
SString sql = "UPDATE book SET isbn ='12EEE', title = ' '', '";
Query nativeQuery = em.createNativeQuery(sql);
nativeQuery.executeUpdate();
em.getTransaction().commit();
}Could you please write automatic tests for the previous use cases and update the implementation to have the expected behavior? The number of updated columns may be found considering the number of commas not between two quotes. You may transform the sql String into a char array and iterate on this array to do this. We prefer fast (memory database) integration tests to unit tests because integration tests check the whole implementation. In some specific cases, some unit tests could be interesting. For example, in MaxUpdatedColumnsPerMeasureExtractor we could mock SqlExecutions and write tests for update syntaxes specific to PostgreSQL (not asked in the frame of this pull request but if you are interested you could submit another pull request, we would be happy of that :)) One more time, thanks a lot for your contribution. |
|
I wrote the additional tests: @Test
public void
should_fail_if_no_bind_parameters_and_the_number_of_updated_columns_is_greater_than_the_expected_number() {
// GIVEN
Class<?> testClass = AClassAnnotatedWithExpectMaxUpdatedColumnFailingInCaseOfNoBindParameters.class;
// WHEN
PrintableResult printableResult = PrintableResult.testResult(testClass);
// THEN
SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(printableResult.failureCount()).isEqualTo(1);
softAssertions.assertThat(printableResult.toString())
.contains("Maximum expected number of updated columns <1> but is <2>.")
.contains("UPDATE")
.contains("book")
;
softAssertions.assertAll();
}
@Test
public void
should_fail_if_no_bind_parameters_and_comma_in_updated_column_and_the_number_of_updated_columns_is_greater_than_the_expected_number() {
// GIVEN
Class<?> testClass = AClassAnnotatedWithExpectMaxUpdatedColumnFailingInCaseOfNoBindParametersAndAQuoteInUpdatedColumn.class;
// WHEN
PrintableResult printableResult = PrintableResult.testResult(testClass);
// THEN
SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(printableResult.failureCount()).isEqualTo(1);
softAssertions.assertThat(printableResult.toString())
.contains("Maximum expected number of updated columns <1> but is <2>.")
.contains("UPDATE")
.contains("book")
;
softAssertions.assertAll();
}
@Test
public void
should_fail_if_no_bind_parameters_and_quote_in_updated_column_and_the_number_of_updated_columns_is_greater_than_the_expected_number() {
// GIVEN
Class<?> testClass = AClassAnnotatedWithExpectMaxUpdatedColumnFailingInCaseOfNoBindParametersAndAQuoteInUpdatedColumn.class;
// WHEN
PrintableResult printableResult = PrintableResult.testResult(testClass);
// THEN
SoftAssertions softAssertions = new SoftAssertions();
softAssertions.assertThat(printableResult.failureCount()).isEqualTo(1);
softAssertions.assertThat(printableResult.toString())
.contains("Maximum expected number of updated columns <1> but is <2>.")
.contains("UPDATE")
.contains("book")
;
softAssertions.assertAll();
}/*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright 2019-2019 the original author or authors.
*/
package org.quickperf.sql.update.column;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.quickperf.junit4.QuickPerfJUnitRunner;
import org.quickperf.sql.SqlTestBase;
import org.quickperf.sql.annotation.ExpectMaxUpdatedColumn;
import javax.persistence.EntityManager;
import javax.persistence.Query;
@RunWith(QuickPerfJUnitRunner.class)
public class AClassAnnotatedWithExpectMaxUpdatedColumnFailingInCaseOfNoBindParameters extends SqlTestBase {
@Test
@ExpectMaxUpdatedColumn(1)
public void execute_update_with_two_columns_updated() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
String sql = "UPDATE book SET isbn ='12EEE', title = 'Book title'";
Query nativeQuery = em.createNativeQuery(sql);
nativeQuery.executeUpdate();
em.getTransaction().commit();
}
}/*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright 2019-2019 the original author or authors.
*/
package org.quickperf.sql.update.column;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.quickperf.junit4.QuickPerfJUnitRunner;
import org.quickperf.sql.SqlTestBase;
import org.quickperf.sql.annotation.ExpectMaxUpdatedColumn;
import javax.persistence.EntityManager;
import javax.persistence.Query;
@RunWith(QuickPerfJUnitRunner.class)
public class AClassAnnotatedWithExpectMaxUpdatedColumnFailingInCaseOfNoBindParametersAndACommaInUpdatedColumn extends SqlTestBase {
@Test
@ExpectMaxUpdatedColumn(1)
public void execute_update_with_two_columns_updated() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
String sql = "UPDATE book SET isbn ='12,EEE', title = 'Book title'";
Query nativeQuery = em.createNativeQuery(sql);
nativeQuery.executeUpdate();
em.getTransaction().commit();
}
}/*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright 2019-2019 the original author or authors.
*/
package org.quickperf.sql.update.column;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.quickperf.junit4.QuickPerfJUnitRunner;
import org.quickperf.sql.SqlTestBase;
import org.quickperf.sql.annotation.ExpectMaxUpdatedColumn;
import javax.persistence.EntityManager;
import javax.persistence.Query;
@RunWith(QuickPerfJUnitRunner.class)
public class AClassAnnotatedWithExpectMaxUpdatedColumnFailingInCaseOfNoBindParametersAndAQuoteInUpdatedColumn extends SqlTestBase {
@Test
@ExpectMaxUpdatedColumn(1)
public void execute_update_with_two_columns_updated() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
String sql = "UPDATE book SET isbn ='12,EEE', title = 'Book title'";
Query nativeQuery = em.createNativeQuery(sql);
nativeQuery.executeUpdate();
em.getTransaction().commit();
}
} |
6d35d6c to
324c10e
Compare
43261de to
a876998
Compare
Motivation
Users might want to ensure that a method to not update more columns that required. By putting
@ExpectMaxUpdatedColumn(3)quickperf wil assert that no more than 3 columns have been updated.Implementation
Context
We want to count columns passed in the update SQL query. We will count the parameter setted in the set clause of the query. We suppose also that with are using
PreparedStatementto execute this update. This is what hibernate do.Counting
How to return
2in this exampleUPDATE book SET isbn = ?, title = ? WHERE id = ?To count updated columns, we cannot rely on
query.getParametersList().get(0)because this list will contains all 3 parameters of the query.Instead we can count the occurrences of the character
?which represent a parameter. We must count those occurrences only on the substringSET isbn = ?, title = ?to exclude?placeholders used elsewhere in the query.Testing
It would be great to unit test the method
SqlExecutions#countUpdatedColumnwith different string query. But the modulesql-annotationsdo not have yet a testing package neither a testing framework.So @jeanbisutti what do you think about adding one ?
Not implemented
According to postgres documentation of Update statement (https://www.postgresql.org/docs/9.1/sql-update.html) :
Update can also contains
FROMorRETURNING. We should consider those keywords also to extract the substring on which we do the count.