java 如何使SpringBootTest将自动连接的示例视为原型?

hivapdat  于 2023-03-06  发布在  Java
关注(0)|答案(1)|浏览(107)

Spring / SpringBoot新手。我有一个代表玩具车经销商的界面:

public interface DealershipService {

  Long getRevenue();

  void sell(Car car);

  void buy(Car car);

  List<Car> findByMake(String make);

  List<Car> findByMakeAndModel(String make, String model);

  List<Car> findByMakeModelAndYear(String make, String model, String year);

  List<Car> findByYearRange(String yearLowInclusive, String yearHighInclusive);

  List<Car> findInCostRange(long costLowInclusive, long costHighInclusive);
}

及其实现,其中只有buy()sell()方法是真正相关的方法:

@Slf4j
@Data
@Service
public class DealershipServiceImpl implements DealershipService {

  @Value("${revenue}")
  private Long revenue;
  private final CarRepository carRepository;

  @Autowired
  public DealershipServiceImpl(CarRepository carRepository) {
    this.carRepository = carRepository;
  }

  @Override
  public void sell(Car car) {
    carRepository.removeFromRepository(car.getVin());
    revenue += car.getCostInUSD();
    log.info("Sold car {}. Current revenue: {}", car, revenue);
  }

  @Override
  public void buy(Car car) {
    if (revenue >= car.getCostInUSD()) {
      carRepository.addToRepository(car);
      revenue -= car.getCostInUSD();
      log.info("Bought car {}. Current revenue: {}", car, revenue);
    } else {
      log.warn("Unable to buy car {}; we're broke!", car);
      throw new InsufficientRevenueException();
    }
  }
.
.
.

买车会减少可用收入,而卖车会增加可用收入。在我的application.properties文件中(在maintest下),revenue的价值是1_000_000L(据推测是100万美元)。
为了测试这个实现,我编写了以下代码:

@SpringBootTest(classes =  TestConfig.class)
public class DealershipServiceIT {

    @Autowired
    private  DealershipService dealershipService;

    @Test
    public void whenNoTransactions_TotalRevenueIsAMil(){
        assertThat(dealershipService.getRevenue(), is(1_000_000L));
    }

    @Test
    public void whenMakingTransactions_revenueIsAffected(){
        Car car = Car.builder().year(2006).vin("1234").costInUSD(10_000L).make("Nissan").model("Sentra").build();
        dealershipService.buy(car);
        assertThat(dealershipService.getRevenue(), is(990_000L));
    }
}

问题是whenMakingTransactions_revenueIsAffected()的动作影响了注入到类中的单例字段dealershipService,因此,当我运行类的所有测试时,这个测试首先运行(我不知道为什么测试没有按照编写的顺序运行),这个测试成功而whenNoTransactions_TotalRevenueIsAMil()失败,这是因为收入福尔斯了10 k,然后第一个测试看到了dealershipService的同一个单例示例。
如果我通过在DealershipServiceImpl上添加@Scope("prototype")来使DealershipServiceImpl成为原型bean,这个问题就得到了解决,但是我不太确定这是否是一个好的Spring设计;Bean默认为单例是有原因的。
因此,我希望找到一种方法,将测试中注入的DealershipService视为原型 *,以便进行测试 *,如果可能的话。实际上,无论何时进入新测试,我都需要将新的DealershipService注入测试。使原始DealershipService成为原型是唯一的可能性吗?

xoefb8l8

xoefb8l81#

您的测试重用了应用程序上下文,为了使它们彼此独立,您应该使用@DirtiesContext注解:
@DirtiesContext指示底层Springx 1 m2n1x在测试执行期间已被污染(也就是说,测试以某种方式修改或损坏了它-例如,通过更改单例bean的状态),并且应该关闭。当应用程序上下文被标记为脏时,它将从测试框架的缓存中删除并关闭。因此,底层Spring容器将被重新构建以用于任何需要具有相同配置元数据的上下文的后续测试。
例如,您可以如下所示注解测试类:

@SpringBootTest(classes =  TestConfig.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class DealershipServiceIT {
//..
}

相关问题