Spring的`JpaRepository`仅应在测试范围内使用

huangapple go评论65阅读模式
英文:

Spring `JpaRepository` to be used only in test scope

问题

我有一个`JpaRepository`,看起来像这样

```java
@Repository
public interface CustomRepository extends JpaRepository<EntityType, Integer> {
    // 方法
}

可能会有一些可能运行很长时间的查询,这种情况下我需要强制执行超时。我已经成功添加了与超时相关的配置(如果使用的连接池是Druid,可能会有所影响),现在我想在单元测试中对其进行测试。我在我的JpaRepository<T, ID>接口中使用了以下方法:

@Query(value = "SELECT benchmark(:count, MD5('3094803'))", nativeQuery = true)
void run(@Param("count") Long count);

这个方法成功运行并展示了预期的行为。然而,考虑到这个方法的运行时间会随着参数count的增加而变长,仅出于测试超时的目的就将其放在生产代码中,让我感到非常不舒服,因为这可能最终会成为一个可以被利用发起拒绝服务攻击的漏洞。

因此,针对这个问题,是否有办法在我的测试范围内使用这个完全相同的方法,而不必将其放入生产代码中?


<details>
<summary>英文:</summary>

I have a `JpaRepository`, that looks like

@Repository
public interface CustomRepository extends JpaRepository<EntityType, Integer> {
// Methods
}

which could possibly have queries that would run for long, in which case I need to enforce a timeout. I have successfully added the timeout-related configuration (the connection pool being used is `Druid`, if that matters) and now I want to test it in a unit test. I am using the following method in my `JpaRepository&lt;T, ID&gt;` interface.

@Query(value = "SELECT benchmark(:count, MD5('3094803'))", nativeQuery = true)
void run(@Param("count") Long count);


This method runs successfully and demonstrates the expected behavior. However, given that this method will run longer as the value given to parameter `count` becomes larger, having this in the production code, just for the sake of testing the timeouts, bothers me to my core, as this might end up being a vulnerability that could be leveraged to launch a denial attack.

So to the question, is some way I can use this exact method in my test scope, without having that going in the production code?

</details>


# 答案1
**得分**: 0

结果证明,事情并不是那么复杂。考虑到这个项目是在 Spring 上运行的,我可以在我的测试源代码中扩展上面的存储库,如下所示。

```java
package com.project.package.repo;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface TimedCustomRepository extends CustomRepository {
    @Query(value = "SELECT benchmark(:count, MD5('3094803'))", nativeQuery = true)
    void run(@Param("count") Long count);
}

由于我使用的是 JUnit4,我可以拥有一个在 Spring Boot 上运行的测试类,如下所示。

package com.project.package.repo;

import com.github.database.rider.spring.api.DBRider;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
@DBRider(dataSourceBeanName = "primaryDataSource") // 数据源连接;不是很重要。
public class TransactionHistoryJpaRepoTest {

    @Autowired //---(1)
    private TimedCustomRepository timedCustomRepository;

    @Test(expected = JpaSystemException.class)
    public void whenQueryTimeoutOccurs() {
        timedCustomRepository.run(100000000L);
    }
}

(1) 处的属性将使用我们上面创建的存储库 bean 进行连接,这个测试将如预期般执行。由于 TimedCustomRepository 这个 bean 扩展了 CustomRepository,数据源配置和其他所有内容都将保持相同。最重要的是,由于这个包含长时间运行查询的方法现在仅在测试范围内,它不会对测试范围之外产生任何影响。

英文:

Turns out, it's not that complicated. Given that this project is running on Spring, I can have an extension of the above repository in my test sources, as follows.

package com.project.package.repo;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface TimedCustomRepository extends CustomRepository {
    @Query(value = &quot;SELECT benchmark(:count, MD5(&#39;3094803&#39;))&quot;, nativeQuery = true)
    void run(@Param(&quot;count&quot;) Long count);
}

As I have JUnit4, I can have a test class which will run on Spring boot, like follows.

package om.project.package.repo;

import com.github.database.rider.spring.api.DBRider;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
@DBRider(dataSourceBeanName = &quot;primaryDataSource&quot;) //Data source wiring; Not that important.
public class TransactionHistoryJpaRepoTest {

    @Autowired //---(1)
    private TimedCustomRepository timedCustomRepository;

    @Test(expected = JpaSystemException.class)
    public void whenQueryTimeoutOccurs() {
        timedCustomRepository.run(100000000L);
    }
}

The property at (1) will be wired using the repository bean which we have created above, and this test will execute as expected. Given the bean TimedCustomRepository extends CustomRepository, the data source configuration and everything will be the same. Most importantly, since this method with a long running query is now only on the test scope, it will not have any impact beyond the test scope.

huangapple
  • 本文由 发表于 2020年9月16日 16:00:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/63915616.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定