【问题标题】:How to release the port number after every JUnit test in spring boot application?如何在 Spring Boot 应用程序中每次 JUnit 测试后释放端口号?
【发布时间】:2017-11-21 23:31:30
【问题描述】:

我有一个用 Spring Boot 编写的 JUnit 测试类,其中包含 3 个单元测试:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
@ContextConfiguration
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class AppclaitionTest {

    @BeforeClass
    public static void initialize(){
        System.out.println(">>>>>>>Intialization Part!");
    }

    @Test
    public void test1(){
        System.out.println(">>>>>>>Appcliation Test Started! - Test 1");
        Application.main(new String[]{});
        System.out.println(">>>>>>>Appcliation Test Ended! - Test 1");
    }

    @Test
    public void test2(){
        System.out.println(">>>>>>>Appcliation Test Started! - Test 2");
        Application.main(new String[]{});
        System.out.println(">>>>>>>Appcliation Test Ended! - Test 2");
    }

    @Test
    public void test3(){
        System.out.println(">>>>>>>Appcliation Test Started! - Test 3");
        Application.main(new String[]{});
        System.out.println(">>>>>>>Appcliation Test Ended! - Test 3");
    }

    @AfterClass
    public static void destory(){
        System.out.println(">>>>>>>Destroy Part!");
    }
}

如果在第一次测试后运行,我会遇到异常:

java.net.BindException: Address already in use: bind

虽然释放了应用程序上下文,但它没有释放端口号,因此我得到了上述异常。

有什么方法可以在每次单元测试前关闭端口号?

【问题讨论】:

    标签: java unit-testing spring-boot junit


    【解决方案1】:

    使用@After@Before 处理每个单元测试的调用前后。

    【讨论】:

    • 有什么方法可以在每次单元测试后停止 Spring Boot 应用程序?
    • 也许您需要使用SpringApplication 来启动和停止您的应用程序。
    【解决方案2】:

    由于不止一个 springboot 测试,您可能会遇到问题,并且您可能正在使用诸如surefire之类的东西来并行执行测试类。

    使用 Spring boot,您可以随机化每个 junit 类中的端口,如下所述。但请注意,这将是课堂级别,而不是测试级别。

    但我真的没有看到方法级别的需求。 Springboot 测试很慢,所以我建议不要这样做。

    @SpringBootTest(classes = Application.class,webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

    【讨论】:

      【解决方案3】:

      您应该考虑使用SpringApplication 类来启动您的Spring Boot 应用程序,而不是直接调用不提供API 来终止它的Spring Boot 应用程序的main(String[] args) 方法。

      使用SpringApplication 方式,您可以获得一个ConfigurableApplicationContext 实例,该实例提供了一种终止正在运行的应用程序的方法。

      例如:

      ConfigurableApplicationContext context;
      
      @Before
      public void setup{
          SpringApplication springApplication = new SpringApplicationBuilder()           
                  .sources(Application.class)
                  .build();
          context = springApplication.run();
      }
      
      @After
      public void tearDown(){
          SpringApplication.exit(context);
      }
      
      @Test
       public void test1(){         
          // action
             ...
          // assertion
             ...
       }
      

      但是,您应该谨慎对待这种方式。
      启动 Spring Boot 应用程序是一项相对昂贵的操作。
      为任何测试方法执行它都会减慢测试的执行速度。
      单元测试应该很快。
      在集成机器上执行的集成测试可能会更慢。
      您还应该考虑到这个问题。

      【讨论】:

      • SpringApplicationBuilder 以前的版本(1.1.4)不包含构建应用程序和启动的构建方法。因此,我将代码更改为: 解决方案 1: context = new SpringApplicationBuilder(Application.class).web(false).run();方案二:SpringApplicationBuilder app = new SpringApplicationBuilder(Application.class); app.sources(Application.class);应用程序.web(假);上下文 = app.run();但在这两种情况下,应用程序都没有启动。
      • 您可能需要使用 {@BeforeEach} 和 {@AfterEach} 根据此回复:stackoverflow.com/a/51515680/1617124
      • @Lars 这是可能的。我的答案依赖于 JUnit4,而另一个依赖于 JUnit5。
      猜你喜欢
      • 1970-01-01
      • 2018-07-22
      • 2016-04-05
      • 2022-01-15
      • 2017-03-07
      • 2021-11-24
      • 2012-03-20
      • 2021-05-17
      • 1970-01-01
      相关资源
      最近更新 更多