Анонімні простори імен роблять код нестабільним


12

Ось типовий код C ++:

foo.hpp

#pragma once

class Foo {
public:
  void f();
  void g();
  ...
};

foo.cpp

#include "foo.hpp"

namespace {
    const int kUpperX = 111;
    const int kAlternativeX = 222;

    bool match(int x) {
      return x < kUpperX || x == kAlternativeX;
    }
} // namespace

void Foo::f() {
  ...
  if (match(x)) return;
  ...

Це схоже на гідний ідіоматичний код C ++ - клас, хелперна функція, matchяка використовується методами Foo, деякі константи для цієї хелперної функції.

А потім я хочу написати тести.
Було б цілком логічно написати окремий тест для одиниць match, тому що це зовсім нетривіально.
Але він знаходиться в анонімному просторі імен.
Звичайно, я можу написати тест, який би зателефонував Foo::f(). Однак це не буде хорошим тестом, якщо Fooвін важкий і складний, такий тест не ізолюватиме перевіреного від інших непов'язаних факторів.

Тому я повинен перемістити matchі все інше з анонімного простору імен.

Питання: який сенс вводити функції та константи в анонімний простір імен, якщо це робить їх непридатними в тестах?


3
@ BЈовић перечитайте код - у анонімному просторі імен є foo.cpp, а не в заголовку! ОП, здається, добре розуміє, що не слід ставити не заголовки імен у заголовок.
амон

Деяка ідея у тестуванні блоку C ++ у коді без імені безіменного імені ... але «суть» у тому, що інкапсуляція хороша. Зрештою, це та сама проблема, що і у функцій приватних членів: їх не можна протестувати без нав'язкового характеру, але ви не хочете відмовлятися від інформації, прихованої для тестування одиниць (наприклад, stackoverflow.com/a/3676680/3235496 ).
manlio

1
Ваш випадок концептуально не сильно відрізняється від випадку тестування (чи не тестування) приватних методів. Тож, коли ви шукаєте "тест-одиничне тестування" тут, у програмістів, ви отримаєте безліч відповідей, які зможете застосувати безпосередньо до своєї справи.
Док Браун

@DocBrown Мене не запитують, як тестувати функції anon. простори імен. Я запитую "навіщо вводити код у anon. Простори імен?" (див. текст у кінці запитання). Звинувачуйте Іксрека в зміні заголовка на щось інше.
Абікс

2
@Abyx: в тих інших відповідях, про які я згадував вище, ви знайдете великий консенсус багатьох експертів тут про те, що перевірити приватні методи дійсно погано, і що зловживання friendключовим словом для цієї мети не рекомендується. Поєднуйте це з вашим припущенням що якщо обмеження методу призводить до ситуації, коли ви більше не можете його тестувати, це означає, що приватні методи не були б корисними.
Doc Brown

Відповіді:


7

Якщо ви хочете випробувати тест приватних даних про реалізацію, ви виконайте те ж саме ухилення для неназваних просторів імен, що і для приватних (або захищених) членів класу:

Прорив у та вечірка.

У той час як для класів ви зловживаєте friend, для безіменних просторів імен ви зловживаєте #include-механізмом, який навіть не змушує вас змінити код.
Тепер, коли ваш тестовий код (або краще лише щось викрити все) знаходиться в одному ТУ, проблем немає.

Слово застереження: Якщо ви протестуєте деталі реалізації, ваш тест буде порушений, якщо вони зміниться. Будьте впевнені, протестуйте лише ті деталі реалізації, які все одно просочуються, або прийміть, що ваш тест є незвично ефемерним.


6

Функція у вашому прикладі виглядає досить складною, і, можливо, краще перенести її в заголовок, з метою тестування одиниць.

який сенс вводити функції та константи в анонімний простір імен, якщо це робить їх непридатними в тестах?

Щоб зробити їх ізольованими від решти світу. І в анонімному просторі імен ви можете розміщувати не лише функції та константи - це також для типів.

Однак якщо це робить тести вашого блоку дуже складними, ви робите це неправильно. У такому випадку функція там не належить. Тоді настав час трохи рефакторингу, щоб зробити тестування простішим.

Таким чином, в анонімному просторі імен повинні працювати лише дуже прості функції, іноді константи та типи (включаючи typedefs), що використовуються в цьому блоці перекладу.


5

Було б цілком логічно написати окремий одиничний тест на відповідність, тому що це зовсім нетривіально.

Код, який ви показали, match- це досить тривіальний 1-вкладиш без будь-яких складних крайових випадків, чи це як спрощений приклад? У будь-якому випадку, я вважаю, що це спрощено ...

Питання: який сенс вводити функції та константи в анонімний простір імен, якщо це робить їх непридатними в тестах?

Це питання саме те, що хотів змусити мене заскочити сюди, оскільки Дедуплікатор вже показав ідеально хороший спосіб прорватися та отримати доступ через #includeхитрість. Але формулювання тут виглядає як тестування кожної внутрішньої деталі впровадження всього - це якась універсальна кінцева мета, коли вона далека від неї.

Мета рівномірного тестування одиниць не завжди є тестуванням кожного маленького зернистого внутрішнього мікро-блоку функціональності. Це ж питання стосується і статичних функцій файлового діапазону в C. На це питання можна навіть важче відповісти, запитуючи, чому розробники використовують pimplsC ++, що вимагатиме як хитрості, такfriendship і #includeхитрості білого поля, торгуючи легкою доказовістю деталей впровадження для покращеного часу компіляції, напр

З певної прагматичної точки зору, це може здатися грубим, але matchможе бути неправильно виконаним у деяких крайніх випадках, які спричиняють його зростання. Однак якщо єдиний зовнішній клас, Fooякий має доступ, matchне може використовувати його таким чином, що стикається з цими крайовими випадками, то це правильне значення для правильності того, Fooщо matchмає ці крайові випадки, які ніколи не будуть зустрічатися, якщо не Fooзміниться, в який момент тести Fooне вдасться, і ми дізнаємось негайно.

Більш нав’язливий склад мислення, який прагне перевірити кожну деталь внутрішнього впровадження (можливо, критично важливе програмне забезпечення, наприклад), може захотіти проникнути в партію, але багато людей не обов'язково вважають, що це найкраща ідея, оскільки це створило б найбільш крихкі тести, які можна уявити. YMMV. Але я просто хотів зайнятись формулюванням цього питання, завдяки чому таке звучання убер-дрібнозернистого-внутрішнього-детального рівня має бути кінцевою метою, коли навіть найсуворіший настрій тестування міркувань може трохи розслабитися тут і уникати рентгенівських зйомок у кожного класу.

То чому люди визначають функції в анонімних просторах імен у C ++ або як статичні функції в області файлів із внутрішнім зв’язком у C, прихованому від зовнішнього світу? І це головним чином: приховати їх від зовнішнього світу. Це має ряд ефектів від скорочення часу компіляції до зменшення складності (те, що не можна отримати в іншому місці, не може спричинити проблем в інших місцях) тощо. Можливо, перевіряється інформація про приватну / внутрішню реалізацію - це не річ номер один у свідомості людей, коли вони це роблять, скажімо, скорочуючи час створення та приховуючи зайву складність від зовнішнього світу.


Я б хотів, щоб я міг підкреслити це десять разів. Як дотична інформація, пов’язана з критичним програмним забезпеченням із високим рівнем надійності, ви набагато більше переймаєтесь правильністю деталей. Цей ідіоматичний стиль для C ++ для цього не підходить. Я б не використовував такі функції мови, як анонімні простори імен або проксі-подібні шаблони. Я б контролював свою межу грубо із [підтримуваними] заголовками простору користувачів та [непідтримуваними] заголовками простору розробника.
Девід
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.