Как подтвердить количество утверждений (или каким-либо другим способом обеспечить, чтобы все члены были проверены в утверждении)? - PullRequest
0 голосов
/ 07 января 2019

В определенном модульном тесте для моего класса я хочу подтвердить, что утверждение было написано для всех полей-членов. То есть, учитывая

public class Foo {
  int a;
  int b;
  String c;
}

Я хочу сделать что-то вроде

@Test
public void testFieldsAgainstExternalModel(Foo model, Bar externalModel) {
  assertEquals(model.a, externalModel.getA());
  assertEquals(model.b, externalModel.getSomethingNamedDifferently());
  assertEquals(model.c, externalModel.getC().toString());
  assertNumberOfAssertionsInThisTest(3); // <-- How do I do this?
}

Конечно, подсчет количества утверждений не гарантирует, что они имеют какое-либо отношение к каждому полю, имеющему утверждение. Но я просто пытаюсь написать тест, который не выполняется, если разработчик добавляет поле к Foo и забывает обновить этот тест.

  • Наивный подход: Самая простая вещь, о которой я могу подумать, - это использовать отражение для определения количества полей, которые есть у 1014 *, , например assertEquals(3, Foo.getDeclaredFields().count()). Но я легко вижу, как программист увеличивает число без фактического добавления утверждения.

  • Все еще наивный подход, но приемлемый: Я думаю, что если я смогу по крайней мере посчитать количество утверждений, это в достаточной степени приведет программистов к намеченной потребности.

  • Более точные подходы: Конечно, кажется, что лучший подход состоит в том, чтобы фактически сохранить таблицу, в которой поля появились в утверждении ( например с помощью метода-обертки, такого как assertEqualsWithCounters), но на самом деле моя ситуация немного сложнее. Например, моя модель на самом деле является сгенерированным классом (@AutoMatter), и я буду использовать геттеры с обеих сторон утверждения, так что будет трудно определить, какое поле было «затронуто» утверждением. Вот почему мне проще всего считать утверждения и не зависеть от фактических типов и значений.

Ответы [ 3 ]

0 голосов
/ 07 января 2019

Но я просто пытаюсь написать тест, который не удается, если разработчик добавляет поле для Foo и забывает обновить этот тест.

Моя компания использует инфраструктуру сопоставления для сопоставления bean-компонентов из базы данных, поля один к одному с базой данных, с bean-компонентом модели, который мы возвращаем клиенту, который мы можем изменять по мере необходимости. Я считаю, что это общий случай использования и, по сути, то, что вы пытаетесь достичь. Вы должны быть меньше озабочены тестированием изменений на Foo, и больше заботиться о том, чтобы ничто не нарушало отображение от Foo до Bar.

Class BeanDb{
 private int a;
 private int b;
 ...
}

Class Bean{
 private int a;
 private int b;
 private String somethingElse;
 ...
}

Затем у нас есть тест proivder, который использует isEqualToComparingFieldByFieldRecursively для сравнения двух бинов.

private Bean bean = new Bean();
private Bean beanDb = new BeanDb();
private BeanProvider provider = new BeanProvider();

@Before
public void setup(){
 bean.setA(1);
 bean.setB(2);

 beanDb.setA(1);
 beanDb.setB(2);
}

@Test
public void prepareForDatabase(){
    BeanDb db = provider.prepareForDatabase(bean);

    assertThat(beanDb).isEqualToComparingFieldByFieldRecursively(db);
}

@Test
public void populateFromDatabase(){
    Bean model = provider.populateFromDatabase(beanDb);

    assertThat(model).isEqualToComparingFieldByFieldRecursively(bean);
}

Это на самом деле ловит много ошибок. Если что-то изменится в bean-компоненте bean / db, тест прекратится в нашем наборе непрерывных интеграций. Предостережение заключается в том, что isEqualToComparingFieldByFieldRecursively не будет перехватывать вновь добавленные поля. Когда я проверяю запросы кода / извлечения и BeanDb или провайдер был обновлен, я спрашиваю: «Вы обновили тест провайдера?»

0 голосов
/ 07 января 2019

Я думаю, что ответ на

assertNumberOfAssertionsInThisTest(3); // <-- How do I do this?

- это: вы делаете , а не делаете это. Этот тест близок к бесполезному.

Если есть только 3 поля, вы можете увидеть своими глазами, что вы проверяете эти три поля. Вы, вероятно, думаете о 15 полях в этом классе, но тогда:

assertEquals(model.a, externalModel.getA());
assertEquals(model.b, externalModel.getSomethingNamedDifferently());
assertEquals(model.c, externalModel.getC().toString());
assertEquals(model.c, externalModel.getC().toString());
assertEquals(model.d, externalModel.getD().toString());

... assertEquals (model.o, externalModel.getO (). toString ());

assertNumberOfAssertionsInThisTest(15); 

не не поможет вам. Угадайте, что: когда я собрал свой фальшивый пример, я пропустил свойство 14 (model.n), но вместо этого у меня была ошибка копирования / вставки, и я дважды проверил model.c, что привело к общему количеству 15.

Поэтому я согласен с пользователем Филом, просто предлагая еще один подход, такой как:

  • гарантирует, что классы бинов имеют разумные equals() (и, возможно, hashCode() методы). Либо с помощью Lombok, либо с помощью базового класса бинов, который использует EqualsBuilder (мы на самом деле делаем это позже в наших проектах)
  • затем используйте тестовый код или используйте фиктивный бин и просто сравните, если этот фальшивый бин равен с бином, который ваш производственный код создал из (возможно, фальсифицированного) объекта внешней модели.
0 голосов
/ 07 января 2019

Я думаю, вам может понадобиться PowerMockito как Mockito не поддерживает насмешливые статические методы .

Я не тестировал приведенный ниже код, но моя идея заключается в следующем:

@RunWith(PowerMockRunner.class)
public class Tester {
    public class Foo {
        int a = 5;
        int b = 6;
        String c = "7";
    }
    class Bar {

        public int getA() {
            return 5;
        }

        public int getSomethingNamedDifferently() {
            return 6;
        }

        public Integer getC() {
            return 7;
        }
    }

    @Test
    public void testFieldsAgainstExternalModel() {
        testFieldsAgainstExternalModel(new Foo(), new Bar());
    }
    public void testFieldsAgainstExternalModel(Foo model, Bar externalModel) {
        Assert spiedAssert = PowerMockito.spy(Assert.class);

        spiedAssert.assertEquals(model.a, externalModel.getA());
        spiedAssert.assertEquals(model.b, externalModel.getSomethingNamedDifferently());
        spiedAssert.assertEquals(model.c, externalModel.getC().toString());
        PowerMockito.verify(spiedAssert, times(3)).assertEquals(any(), any());
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...