java 模拟编辑输入的方法

d6kp6zgx  于 2023-05-21  发布在  Java
关注(0)|答案(2)|浏览(158)

我试图模拟一个dao方法,它创建一个记录,然后在输入上设置id。
下面是一些伪代码
抽样检验

RecordDto input = new RecordDto();
input.setId(null);
input.setName("test");

when(dao.createRecord(any(RecordDto.class)).thenReturn(1);

createSomething(input);

模拟方法

public int createRecord(RecordDto input) {
   int updatedRowCount = 0;
   int primaryKey = db call to create record
   rows += primary != null ? 1 : 0;
   input.setId(primaryKey) <-
   return updateRowCount;
}

被测类

public void createSomething(RecordDto input)
   int rowsUpdated = dao.createRecord(input);
   if (input.getId() != null) {
      do something <- this code can not be reached from my test
      because my mock only sets the return value. It needs to also
      modify the input.id.
   }

一旦在我的真实的类中调用了这个方法,输入就有了一个id。我的mock只返回1作为行计数,但id仍然为空。

mwngjboj

mwngjboj1#

我的猜测是,你只是在dao方法内部模拟值返回,但不是副作用。您正在将RecordDto作为参数传递,执行一些操作并调用修改接收到的参数状态的方法。解决方案是使用doAnswer,它不仅允许您返回值,还可以添加一些额外的逻辑。所以,你的测试应该看起来像这样:

@Test
public void test() {
    dao = mock(Dao.class);
    RecordDto input = new RecordDto();
    Integer someRandomId = 15;
    Integer randomRowsUpdated = 3;
    Answer<Integer> answer = new Answer<Integer>() {
        public Integer answer(InvocationOnMock invocation) {
            RecordDto input = invocation.getArgument(0, RecordDto.class); // get the argument received in `createRecord`
            input.setId(someRandomId); // set the new id
            return randomRowsUpdated; // the value to be returned by `createdRecord`
        }
    };
    doAnswer(answer).when(dao).createRecord(input); // using doAnswer instead of doReturn
    createSomething(input);
}

这将是快速的解决方案。
我认为这并不是最好的方法。在方法内部执行副作用可能会在将来导致bug,并且很难知道问题的根本原因,甚至很难进行调试。返回一个RecordDto或另一个自定义对象,让你知道新的id和受影响的行或类似的东西,这将使你的测试更容易设置,也使Assert。

hmae6n7t

hmae6n7t2#

如果您需要一些额外的mocking行为,而不是简单地返回一个值,您可以在when mocking存根中使用thenAnswer而不是thenReturn
我希望这个(过于)简化的例子能有所帮助:

@Mock
   private Bar executor;

   @Test
   public void testMutation() {
      Foo foo = new Foo();

      when(executor.mutate(foo)).thenAnswer(a -> {
         int mockedId = 10;
         Foo input = a.getArgument(0);
         input.setId(mockedId); // mutate the parameter from the method signature
         return mockedId;
      });

      executor.mutate(foo);
      Assertions.assertEquals(10, foo.getId());
   }

   //---- boiler plate code of the DTO and method that mutates the value
   public class Bar {

      public int mutate(Foo input) {
         input.setId(3);
         return 3;
      }
   }

   public class Foo {
      private int id;

      public int getId() {
         return id;
      }

      public void setId(int id) {
         this.id = id;
      }
   }

相关问题