【问题标题】:Is a mock MongoRepository saving objects?模拟 MongoRepository 是否保存对象?
【发布时间】:2018-07-31 18:09:29
【问题描述】:

我正在使用 SpringBoot 1.5.9 并尝试进行集成测试。奇怪的是 MongoRepository.save() 方法在模拟 MongoRepository 上调用时会更新对象。

我有一个计数器类

public class Counter {
     public String id;
     public int seq;

     public void increaseSeq() {
        this.seq += 1;
     }
}

还有他的仓库

public interface CounterRepository extends MongoRepository<Counter, String>{
    Counter findById(String id);
    List<Counter> findAll();
}

还有他的服务

@Service
public class CounterService {
    @Autowired private CounterRepository counterRepository;


    public Counter findCounter(String id) {
        return counterRepository.findById(id);
    }

    public int getSeqAndIncrease(String id) {
        Counter counter = findCounter(id);
        if (counter == null) {
            return -1;
         }

        counter.increaseSeq();

        counterRepository.save(counter);

        return counter.getSeq();
    }
}

现在,当我进行系统集成并尝试模拟 counterRepository 时,它会发生一些我没想到的事情。 counterRepository.findById() 返回一个 Counter 对象,其中增加了 'seq' 字段。为什么? counterRepository.save() 是否以任何方式影响结果(counterRepository 被模拟,因此我认为 save() 不应该有任何影响)?

@RunWith(SpringRunner.class)
@SpringBootTest
public class FlowServiceTest {
    @MockBean private CounterRepository counterRepository;
    @Autowired private CounterService counterService;

    @Before
    public void setUp() {  
     Mockito.when(counterRepository.save(any(Counter.class))).then(arg -> arg.getArgumentAt(0, Counter.class));
     Mockito.when(counterRepository.findById("flow")).thenReturn(new Counter("flow", 10));
    }

    @Test
    public void testSavingInDatabase() {
        System.out.println(counterRepository.findById("flow"));

        counterService.getSeqAndIncreaseSafe("flow");
        System.out.println(counterRepository.findById("flow"));

        counterService.getSeqAndIncreaseSafe("flow");
        System.out.println(counterRepository.findById("flow"));
    }
}

它打印“10 11 12”。为什么不打印'10 10 10'?

【问题讨论】:

  • 在你的测试类中你是如何初始化 counterService 的?
  • @pvpkiran 是的,我初始化了它;忘了写在问题中;不是我更新了它;您是否发现其他可能导致错误的内容?

标签: spring spring-mvc spring-boot spring-data spring-boot-test


【解决方案1】:

问题出在这几行

counterRepository.save(counter);
return counter.getSeq();

你应该做的是这个

Counter saveCounter = counterRepository.save(counter);
return savedCounter.getSeq();

在 getSeqAndIncrease 方法中,您不会返回已保存对象的序列。
通过这样做,您使 save 的模拟语句变得无用。因为你没有使用从 mock 返回的值。

【讨论】:

  • 还是不行。我相信问题来自Mockito。设置 'Mockito.when(counterRepository.findById("flow")).thenReturn(new Counter("flow", 10));' 时,每次都返回一个新对象似乎很直观,但返回对象仅被初始化测试开始时一次,将在所有后续调用中返回。
  • 然后,在我的代码中我执行 counter.increaseSeq();这增加了找到对象的“序列”(这个对象来自 Mockito)。然后在下一次调用时,Mockito 返回同时更新的第一个初始化对象; Mockito 并没有像看起来那样返回一个新对象。
  • 是的,返回的对象在 mockito 中只初始化一次。所以你基本上每次都得到相同的引用,因为它是一个引用而不是一个新对象,所以值会更新
【解决方案2】:

tl;dr - 从 mock 返回的对象在 mockito 中只初始化一次。所以我基本上每次都得到相同的引用,并且由于它是引用而不是新对象,因此值会更新。

完整答案:设置时

Mockito.when(counterRepository.findById("flow")).thenReturn(new Counter("flow", 10));

,每次都返回一个新对象似乎很直观,但返回对象仅在测试开始时初始化一次,并将在所有后续调用中返回。

然后,在我的代码中我会这样做

counter.increaseSeq(); 

这增加了找到对象的“seq”(这个对象来自 Mockito)。然后在下一次调用时,Mockito 返回同时更新的第一个初始化对象; Mockito 并没有像看起来那样返回一个新对象。

【讨论】:

    猜你喜欢
    • 2020-10-08
    • 2021-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多