@may_1997

Как реализовывается функцию(main), которая будет производить проверку?

class String 
{
private: 
	int len;	
	char *str; 	
public:
	// конструктор по умолчанию 
	String () 
	{
		str = new char[1];
		*str = 0; // код пуст симв
		len = 0;
		std::cout << "k po ymolch \n";
	}
	// конструктор с параметром
	String (char *a) 
	{ 
		std::cout<<"param \n";
		int j = 0;
		while (a[j] != 0)
			j++;
		str = new char[j + 1];
		for (int i = 0; i <= j; i++)
			str[i] = a[i];
		

	}
	// копирующий конструктор
	String(const String & b)
	{	
		len = b.len;
		str = new char[len + 1];
		for (int i = 0; i <= len; i++)
			str[i] = b.str[i];
                std::cout<<"kopy  \n";

	}
	
	~String ()  // деструктор
	{
		delete[] str;
		std::cout<<"delete \n";
	}

	// оператор присваивания
	String & operator =(const String &b)
	{	
		std::cout<<"prisv \n";
		delete[] str;
		len = b.len;
		str = new char[len + 1];
		for (int i = 0; i <= len; i++)
			str[i] = b.str[i];
	}
	String operator +(const String &b) const
	{
		String c;
		c.len = b.len + len;
		c.str = new char[c.len + 1];
		for (int i = 0; i < len; i++)
			str[i] = str[i];
		for (int i = len; i <= c.len; i++)
			str[i] = b.str[i - len];
		std::cout<<"concat + \n";
	}

	String & operator +=(const String &b) 
	{
		*this = *this + b;
		return (*this);
		std::cout<<"concat += \n";
	}
	

	operator const char*() const
	{	
		std::cout<<"priv \n";
		return (str);
	}
	
	char & operator [](const int i)
	{	
		std::cout<<"[] \n";
		return(str[i]);
	}
	char operator [](const int i) const
	{
		std::cout<<"[] const \n";
		return(str[i]);
	}
};
  • Вопрос задан
  • 108 просмотров
Решения вопроса 1
@Mercury13
Программист на «си с крестами» и не только
Мы пишем модульный тест собственными силами, без фреймворка. Это значит, что нам надо каким-то образом сымитировать работу фреймворка, но собственными силами и минимумом строчек.

Для удобства нам потребуется одна функция — и немного препроцессорной магии.
#include <iostream>
#include <cstring>

void doAssert(bool condition, int line)
{
    if (condition) {
        std::cout << "Line " << line << " ok" << std::endl;
    } else {
        std::cout << "Line " << line << " FAILED" << std::endl;
    }
}

#define ASSERT(x) doAssert(x, __LINE__)
#define ASSERT_STREQ(x, y) doAssert((std::strcmp(x, y) == 0), __LINE__)


А теперь что-нибудь протестируем. Например, создание строки. Для простоты я проверю не вашу строку, а std::string.
void testStringCreation()
{
    std::string s;
    ASSERT(s.length() == 0);
    ASSERT(s.empty());
    ASSERT_STREQ("", s.c_str());
}

Проверим ещё операцию +=.
void testPlusEq()
{
    std::string s1 = "Alpha";
    std::string s2 = "Bravo";
    s1 += s2;
    ASSERT_STREQ("AlphaBravo", s1.c_str());
}

int main()
{
    testStringCreation();
    testPlusEq();
    return 0;
}

Нужны ещё тесты — создавай новую функцию и вызывай её из main.
Если какой-то тест не проходит — уничтожаем из main все вызовы, кроме несработавшего, и начинаем отладку.

А теперь немного о том, какие должны быть модульные тесты.
1. Изолированные. Если уничтожить часть тестов или запустить их в другом порядке, ничего не должно меняться — при условии, конечно, что никто не обращается к чужой памяти.
2. Каждый модульный тест проверяет одну концепцию, которая указана в его названии. Например: строка создаётся, работает операция +=, и т.д. Будет очень много дублей кода, просто смиритесь с этим.
3. Но нет ничего зазорного, что какой-то тест полагается на концепции, испытанные в других тестах. Если мы испытываем +=, то полагаем, что конструктор копирования работает, и не будем испытывать это.
4. Модульным тестам иногда приходится иметь дело с внутренним поведением объекта. В таком случае объект должен выдавать наружу некоторую информацию — например, соответствующие функции обычно private, но по какой-то препроцессорной команде они становятся public.
5. Модульные тесты обычно имеют дело с простейшим поведением объекта. Это не нагрузочные тесты, надо с этим просто смириться.
6. Принцип работы теста таков. Создать исходные объекты, убедиться в том, что их ВНУТРЕННЕЕ (неспецифицированное, зависящее от реализации) состояние верное, провести некое действие, убедиться, что действие проведено правильно. Например, пусть строка выделяет память с запасом, и надо проверить, как она расширяется — тогда при присваивании "Alpha" мы убеждаемся, что выделено менее 10 символов, затем проводим s1 += "Bravo", затем убеждаемся, что выделено, например, 16 символов.
7. Но заранее не нужно проверять, верно ли ВНЕШНЕЕ (заспецифицированное) состояние. Если мы пишем s1 = "Alpha", значит, строка равна "Alpha", и точка. Все случаи, возможные в операции string = char*, разумеется, покрыты другими тестами.
8. Если вдруг в «боевом» коде обнаружится ошибка, надо сделать юнит-тест, её повторяющий, затем исправить ошибку и констатировать, что тест проходит и остальные тесты не «упали».
9. То же самое, если ошибка случилась, когда проверяли другую концепцию. Проверяем +=, а глюк в конструкторе копирования — заводи новый тест, покрывающий эту ошибку.
10. В проверках на равенство принят порядок ASSERT_EQ(что_должно_быть, что_реально_есть).
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы