模拟一个编辑输入的方法

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

Mocking a method that edits the input

问题

以下是您要翻译的内容:

我正在尝试模拟一个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 = 调用数据库创建记录
   rows += primary != null ? 1 : 0;
   input.setId(primaryKey) <-
   return updateRowCount;
}

受测试类

public void createSomething(RecordDto input)
   int rowsUpdated = dao.createRecord(input);
   if (input.getId() != null) {
      做某事 <- 这段代码在我的测试中无法到达
      因为我的模拟仅设置返回值它还需要修改input.id
   }

一旦在我的实际类中调用该方法,输入就会有一个ID。我的模拟只返回行数的1,但ID仍然为null。

英文:

I am trying to mock a dao method that creates a record then sets the id on the input.

here is some psuedo code

sample test

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

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

createSomething(input);

method to mock

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

class under test

public void createSomething(RecordDto input)
   int rowsUpdated = dao.createRecord(input);
   if (input.getId() != null) {
      do something &lt;- 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.
   }

Once the method is called in my real class input has an id. My mock just returns a 1 for the row count but the id is still null.

答案1

得分: 0

如果你需要除了简单返回值之外的一些额外模拟行为,可以在 when 模拟存根中使用 thenAnswer 而不是 thenReturn

希望这个(过于)简化的例子能帮到你:

   @Mock
   private Bar executor;

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

      when(executor.mutate(foo)).thenAnswer(a -&gt; {
         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());
   }

   //---- DTO和变异值方法的样板代码
   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;
      }
   }
英文:

If you require some additional mocking behavior other than simply returning a value, you can use thenAnswer instead of thenReturn in your when mocking stub.

I hope this (overly) simplified example helps:

   @Mock
   private Bar executor;

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

      when(executor.mutate(foo)).thenAnswer(a -&gt; {
         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;
      }
   }

答案2

得分: 0

My guess is that you are only mocking the value return but not the side effect inside the dao method. You are passing the RecordDto as parameter, doing something and also calling methods that modify the state of the parameter received. The solution for that would be to use doAnswer that lets you not only return a value, you can add some extra logic. So, your test should look like this:

@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);
}

That would be the quick solution.

I would say that this is not exactly the best approach. Doing side effects inside a method could cause bugs in the future, and it will be hard to know the root cause of the problem or even debug. Returning a RecordDto or another custom object that lets you know the new id and the affected rows or something similar will make your tests easier to set up and also make the assertion.

英文:

My guess is that you are only mocking the value return but not the side effect inside the dao method. You are passing the RecordDto as parameter, doing something and also calling methods that modify the state of the parameter received. The solution for that would be to use doAnswer that lets you not only return a value, you can add some extra logic. So, your test should look like this:

@Test
public void test() {
    dao = mock(Dao.class);
    RecordDto input = new RecordDto();
    Integer someRandomId = 15;
    Integer randomRowsUpdated = 3;
    Answer&lt;Integer&gt; answer = new Answer&lt;Integer&gt;() {
        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);
}

That would be the quick solution.

I would say that this is not exactly the best approach. Doing side effects inside a method could cause bugs in a future and it will hard to know the root cause of the problem or even debug. Returning a RecordDto or another custom object that lets you now the new id and the affected rows or something similar will make your tests easier to setup and also make the assertion.

huangapple
  • 本文由 发表于 2023年5月18日 07:46:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76276868.html
匿名

发表评论

匿名网友

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

确定