西电软工程序测试上机

本文围绕西电软工程序测试上机,聚焦C++程序的白盒测试。介绍了使用的工具Microsoft Visual Studio和Google Test模板,详细说明了新建项目步骤,还讲解了头文件和源文件的作用及使用方法,最后阐述在pch.h、pch.cpp和test.cpp中拆分源文件的操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

西电软工程序测试上机

找个做过的大作业做黑白盒测试。黑盒测试就是展示功能,白盒麻烦一点,这篇文章主要讲白盒测试怎么办。

我是用了c++写的贪吃蛇小游戏代码。友情提醒:找个class写的那种,比较方便。

工具

Microsoft Visual Studio (+chatgpt)

在这里插入图片描述
我用的是c++程序,自己去csdn搜教程就好了,记得安装的时候选要用的c++的选项。我们要用这个软件的goole test模板。

开始白盒测试吧

1.新建项目,用google test模板

左上角,文件—新建—项目
在这里插入图片描述
搜索模板,找到google test模板
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
主要就这三个框起来的文件要用。

给大家讲一下这些文件一般是怎么用的。

  • 头文件 (.h 或 .hpp):

通常包含声明(declarations),即函数、类、变量的声明,但不包含具体的实现。
用于描述接口、结构、函数原型等。
通常以 .h 或 .hpp 为文件扩展名,例如 snake.h。

  • 源文件 (.cpp):

包含实际的实现代码。
用于定义头文件中声明的函数和类的具体实现。
通常以 .cpp 为文件扩展名,例如 snake.cpp。

  • #include 指令:

#include 指令用于在一个文件中包含另一个文件的内容。
在头文件中,通常使用 #include 来引入其他头文件,以便使用其他文件中声明的函数、类等。
在源文件中,使用 #include 来引入需要的头文件,确保在使用其他代码之前声明了相应的函数或类。

2.分别在pch.h , pch.cpp 里面把源文件拆分

pch.h放前面一些头文件和宏定义啥的,声明类。
pch.cpp放类的方法内容
test.cpp放测试函数(怎么写goole test的测试看这里看这里),很简单的啦。

可以用chatgpt,让它帮你写,不过会有一些报错,多半是说未分配空间,要自己malloc一下。

我直接拿我的程序打个样吧
pch.h

//
// pch.h
//

#pragma once

#include "gtest/gtest.h"

// 必要的头文件
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <windows.h>
#include <string.h>

using namespace std;

// 定义标记上下左右的明示常量
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
#define ESC 5
#define FOOD 10
// 定义表示位置的结构体类型
typedef struct snake {
	int x;
	int y;
	struct snake* next;
} snake;

class game {
public:
	// 定义全局变量
	int score; // 当前得分
	int speed; // 存储当前速度
	int status;
	snake* tail, * head; // 存储蛇头蛇尾
	snake* food, * q;// q用于遍历链表
	//HANDLE hOUT;
	//函数
	game() {
		score = 0; // 当前得分
		speed = 100; // 存储当前速度
		status = RIGHT;

		snake* tail = new snake;
		snake* head = new snake; // 存储蛇头蛇尾
		snake* food = new snake;
		snake* q = new snake;// q用于遍历链表

		/*
		snake* tail = (snake*)malloc(sizeof(snake));
		snake* head = (snake*)malloc(sizeof(snake)); // 存储蛇头蛇尾
		snake* food = (snake*)malloc(sizeof(snake));
		snake* q = (snake*)malloc(sizeof(snake));// q用于遍历链表
		*/
	}
	void gotoxy(int x, int y); // 设置光标位置
	int choice(void); // 载入游戏界面
	int color(int c); // 设置字体颜色
	void printGame(void); // 打印游戏界面
	void printSnake(void); // 打印蛇身
	void printFood(void); // 打印食物
	void printTips(void); // 打印提示
	void snakeMove(void); // 主操作函数
	int biteSelf(void); // 判断是否咬到了自己
	int encounterWall(void); // 判断是否撞墙
	void keyboardControl(void); // 获取击键
	void speedUp(void); // 加速
	void speedDown(void); // 减速
	int endGame(void); // 结束函数;
	char* s_gets(char* st, int n); // 读取字符
	void frees(snake*); // 释放内存
};

pch.cpp

//
// pch.cpp
//

#include "pch.h"


void game::gotoxy(int x, int y)
{
	COORD c;
	c.X = x;
	c.Y = y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}

int game::choice(void)
{
	int yourchoice;
	// 画出界面 
	gotoxy(35, 5);
	color(11);
	printf("\t贪吃蛇大作战\n");
	printf("\n\n");
	color(13);
	printf("\t\t★★★★★★★★  Snake!");
	printf("\t\t★★★★★★★★  Snake!");
	gotoxy(25, 15);
	color(12);
	printf("1.进入游戏\t2.查看说明\t3.退出游戏\n");
	color(11);
	printf("请选择:");
	scanf("%d", &yourchoice);
	switch (yourchoice)
	{
	case 1:
		system("cls");
		// 初始化 
		printGame();
		printSnake();
		printFood();
		break;
	case 2:
		system("cls");
		printTips();
		break;
	case 3:
		system("cls");
		gotoxy(30, 10);
		color(11);
		printf("Bye!");
		exit(0);
	default:
		system("cls");
		printf("没有此序号,请输入1,2或3\n");
		Sleep(2000);
		system("cls");
	}
	return yourchoice;
}

int game::color(int c)
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);        //更改文字颜色
	return 0;
}

void game::printGame()
{
	int i, j;
	gotoxy(5, 5);
	printf("游戏载入中...请稍后");
	Sleep(2000);
	system("cls");

	// 打印上下界面
	for (i = 0; i <= 50; i += 2)
	{
		gotoxy(i, 0);
		printf("□");
		gotoxy(i, 25);
		printf("□");
	}
	// 打印左右界面
	for (i = 0; i <= 25; i += 1)
	{
		gotoxy(0, i);
		printf("□");
		gotoxy(50, i);
		printf("□");
	}
	// 打印中间网格
	for (i = 1; i <= 24; i += 1)
	{
		for (j = 2; j <= 48; j += 2)
		{
			gotoxy(j, i);
			color(11);
			printf("■");
		}
	}
	// 打印右侧的规则和计分栏
	gotoxy(60, 13);
	color(10);
	printf("当前分数:%d分,当前速度%d", score, speed);
	gotoxy(60, 15);
	printf("用↑ ↓ ← →分别控制蛇的移动\n");
	gotoxy(60, 18);
	printf("每次获取食物加10分  按下F1加速,F2减速,空格暂停\n");
	gotoxy(60, 20);
	printf("不能撞墙和咬到自己!");
	gotoxy(60, 22);
	printf("速度不低于100,不高于300");
}

void game::printFood(void)
{
	srand((unsigned)time(NULL)); // 利用时钟修改种子 
	food = (snake*)malloc(sizeof(snake));
	food->x = 1; // 初始化x坐标 
	while (food->x % 2 && food->x)
	{
		food->x = rand() % 46 + 2;// 2-48 
	}
	food->y = rand() % 23 + 1; // 1-24 
	q = head; // 不改变头遍历链表 
	while (q->next)
	{
		if (q->x == food->x && q->y == food->y)
		{
			free(food);
			printFood();
		}
		else
		{
			gotoxy(food->x, food->y);
			color(12);
			printf("●");
			break;
		}
	}
}

void game::printTips(void)
{
	color(11);
	printf("***********Tips************\n");
	printf("1.采用合理的速度可以获得更高的分数哦!\n");
	printf("2.一定不要撞到自己或者两边的墙!\n");
	printf("3.游戏过程中按ESC退出游戏!\n");
}

void game::printSnake(void)
{
	int i;
	// 设定蛇尾(16,13),头插入,初始向右 
	tail = (snake*)malloc(sizeof(snake));
	tail->x = 16;
	tail->y = 13;
	tail->next = NULL;
	// 设定初始蛇长是4
	for (i = 1; i <= 4; i++)
	{
		head = (snake*)malloc(sizeof(snake));
		head->next = tail;
		head->x = 16 + 2 * i;
		head->y = 13;
		tail = head; // 头成为尾
	}
	// 输出蛇身
	while (tail->next)
	{
		gotoxy(tail->x, tail->y);
		color(14);
		printf("★");
		tail = tail->next;
	}
}
void game::snakeMove(void)
{
	snake* snakenext;
	snakenext = (snake*)malloc(sizeof(snake));
	if (biteSelf())
	{
		gotoxy(60, 11);
		printf("咬到自己啦!");
		free(snakenext);
		Sleep(1500);
		system("cls");
		exit(0);
	}
	else if (encounterWall())
	{
		gotoxy(60, 11);
		printf("撞到墙啦!");
		free(snakenext);
		Sleep(1500);
		system("cls");
		exit(0);
	}
	else
	{
		// 前两个条件判断完成才开始移动 
		Sleep(350 - speed);
		if (status == UP)
		{
			snakenext->x = head->x;
			snakenext->y = head->y - 1;
			snakenext->next = head;
			head = snakenext;
			q = head;
			food= (snake*)malloc(sizeof(snake));
			if (snakenext->x == food->x && snakenext->y == food->y)
			{
				while (q)
				{
					gotoxy(q->x, q->y);
					color(14);
					printf("★");
					q = q->next;
				}
				score += FOOD;
				gotoxy(60, 13);
				printf("当前分数:%d分,当前速度%d", score, speed);
				printFood();
			}
			else
			{
				while (q->next->next)
				{
					gotoxy(q->x, q->y);
					color(14);
					printf("★");
					q = q->next;
				}
				gotoxy(q->next->x, q->next->y);
				color(11);
				printf("■");
				free(q->next);
				q->next = NULL;
			}
		}
		else if (status == DOWN)
		{
			snakenext->x = head->x;
			snakenext->y = head->y + 1;
			snakenext->next = head;
			head = snakenext;
			q = head;
			if (snakenext->x == food->x && snakenext->y == food->y)
			{
				while (q)
				{
					gotoxy(q->x, q->y);
					color(14);
					printf("★");
					q = q->next;
				}
				score += FOOD;
				gotoxy(60, 13);
				printf("当前分数:%d分,当前速度%d", score, speed);
				printFood();
			}
			else
			{
				while (q->next->next)
				{
					gotoxy(q->x, q->y);
					color(14);
					printf("★");
					q = q->next;
				}
				gotoxy(q->next->x, q->next->y);
				color(11);
				printf("■");
				free(q->next);
				q->next = NULL;
			}
		}
		else if (status == LEFT)
		{
			snakenext->x = head->x - 2;
			snakenext->y = head->y;
			snakenext->next = head;
			head = snakenext;
			q = head;
			if (snakenext->x == food->x && snakenext->y == food->y)
			{
				while (q)
				{
					gotoxy(q->x, q->y);
					color(14);
					printf("★");
					q = q->next;
				}
				score += FOOD;
				gotoxy(60, 13);
				printf("当前分数:%d分,当前速度%d", score, speed);
				printFood();
			}
			else
			{
				while (q->next->next)
				{
					gotoxy(q->x, q->y);
					color(14);
					printf("★");
					q = q->next;
				}
				gotoxy(q->next->x, q->next->y);
				color(11);
				printf("■");
				free(q->next);
				q->next = NULL;
			}
		}
		else if (status == RIGHT)
		{
			snakenext->x = head->x + 2;
			snakenext->y = head->y;
			snakenext->next = head;
			head = snakenext;
			q = head;
			if (snakenext->x == food->x && snakenext->y == food->y)
			{
				while (q)
				{
					gotoxy(q->x, q->y);
					color(14);
					printf("★");
					q = q->next;
				}
				score += FOOD;
				gotoxy(60, 13);
				printf("当前分数:%d分,当前速度%d", score, speed);
				printFood();
			}
			else
			{
				while (q->next->next)
				{
					gotoxy(q->x, q->y);
					color(14);
					printf("★");
					q = q->next;
				}
				gotoxy(q->next->x, q->next->y);
				color(11);
				printf("■");
				free(q->next);
				q->next = NULL;
			}
		}
	}
}

int game::biteSelf(void)
{
	int x = 0; // 默认未咬到自己
	q = head->next;
	// 遍历蛇身 
	while (q)
	{
		if (q->x == head->x && q->y == head->y)
		{
			x = 1;
		}
		q = q->next;
	}

	return x;
}

int game::encounterWall(void)
{
	int x = 0; // 默认未撞到墙

	if (head->x == 0 || head->x == 50 || head->y == 0 || head->y == 25)
		x = 1;

	return x;
}

void game::keyboardControl(void)
{
	status = RIGHT; // 初始蛇向右移动
	while (1)
	{
		if (GetAsyncKeyState(VK_UP) && status != DOWN) // GetAsyncKeyState函数用来判断函数调用时指定虚拟键的状态
		{
			status = UP;           //如果蛇不是向下前进的时候,按上键,执行向上前进操作
		}
		else if (GetAsyncKeyState(VK_DOWN) && status != UP) // 如果蛇不是向上前进的时候,按下键,执行向下前进操作
		{
			status = DOWN;
		}
		else if (GetAsyncKeyState(VK_LEFT) && status != RIGHT) // 如果蛇不是向右前进的时候,按左键,执行向左前进
		{
			status = LEFT;
		}
		else if (GetAsyncKeyState(VK_RIGHT) && status != LEFT) // 如果蛇不是向左前进的时候,按右键,执行向右前进
		{
			status = RIGHT;
		}
		if (GetAsyncKeyState(VK_SPACE))// 空格暂停 
		{
			while (1)
			{
				Sleep(300);
				if (GetAsyncKeyState(VK_SPACE)) // 再次按空格改变状态 
				{
					break;
				}

			}
		}
		else if (GetAsyncKeyState(VK_ESCAPE))
		{
			status = ESC; // 按esc键,直接到结束界面
			if (endGame())
			{
				Sleep(500);
				system("cls");
				break;
			}
		}
		else if (GetAsyncKeyState(VK_F1)) // 按F1键,加速
		{
			speedUp();
			gotoxy(60, 13);
			printf("当前分数:%d分,当前速度%d", score, speed);
		}
		else if (GetAsyncKeyState(VK_F2)) // 按F2键,减速
		{
			speedDown();
			gotoxy(60, 13);
			printf("当前分数:%d分,当前速度%d", score, speed);
		}
		snakeMove();
	}
}

void game::speedUp(void)
{
	if (speed <= 280)
		speed += 20;
}
void game::speedDown(void)
{
	if (speed >= 120)
		speed -= 20;
}

int game::endGame(void)
{
	char x = 0;
	char judge[5];

	getchar();
	gotoxy(60, 9);
	printf("确定退出吗?(Yes/No)");
	gotoxy(60, 11);
	s_gets(judge, 5);

	if (strcmp(judge, "Yes") == 0)
	{
		Sleep(250);
		system("cls");
		gotoxy(40, 11);
		printf("\tBye!");
		x = 1;
	}
	else
		x = 0;

	return x;
}
char* game::s_gets(char* st, int n)
{
	char* ret_val;
	char* find;

	gotoxy(60, 11);
	ret_val = fgets(st, n, stdin);
	if (ret_val)
	{
		find = strchr(st, '\n');
		if (find)
			*find = '\0';
		else
			while (getchar() != '\n')
				continue;
	}

	return ret_val;
}
void game::frees(snake* s)
{
	snake* current = s;

	while (current)
	{
		current = s;
		s = current->next;
		free(current);
	}
}

test.cpp

#include "pch.h"

TEST(SnakeGameTest, printGame) {//打印游戏界面
    game tcs;
    EXPECT_NO_FATAL_FAILURE(tcs.printGame());
    printf("\n\n\n\n\n\n\n\n\n\n\n\n\n测试打印游戏界面结束,准备清空");
    Sleep(2000);
    system("cls");
}

TEST(SnakeGameTest, printTips) {//打印提示
    game tcs;
    // Assuming PrintTips doesn't have any return value, you may need to modify this based on your actual implementation.
    EXPECT_NO_FATAL_FAILURE(tcs.printTips());
    printf("\n\n\n\n\n\n\n测试打印提示结束,准备清空");
    Sleep(2000);
    system("cls");
}

TEST(SnakeGameTest, printSnake) {//打印蛇身
    game tcs;
    // Assuming PrintSnake doesn't have any return value, you may need to modify this based on your actual implementation.
    EXPECT_NO_FATAL_FAILURE(tcs.printSnake());
    printf("\n\n\n\n测试打印蛇身结束,准备清空");
    Sleep(2000);
    system("cls");
}


TEST(SnakeGameTest, snakeMove) {//测试上下左右移动
    game tcs;
    tcs.printGame();
    int i;
    // 设定蛇尾(16,13),头插入,初始向右 ,我们先初始化tail
    tcs.tail = (snake*)malloc(sizeof(snake));
    tcs.tail->x = 16;
    tcs.tail->y = 13;
    tcs.tail->next = NULL;
    // 设定初始蛇长是4
    for (i = 1; i <= 4; i++)
    {
        tcs.head = (snake*)malloc(sizeof(snake));
        tcs.head->next = tcs.tail;
        tcs.head->x = 16 + 2 * i;
        tcs.head->y = 13;
        tcs.tail = tcs.head; // 头成为尾
    }
    int initialX,initialY;

    //上移动
    tcs.status = UP;
    initialY = tcs.head->y;
    tcs.snakeMove();
    EXPECT_EQ(tcs.head->y, initialY - 1);
    //右移动
    tcs.status = RIGHT;
    initialX = tcs.head->x;
    tcs.snakeMove();
    EXPECT_EQ(tcs.head->x, initialX + 2);
    // 下两个 ,避免吃到自己
    tcs.status = DOWN;
    initialY = tcs.head->y;
    tcs.snakeMove();
    tcs.snakeMove();
    EXPECT_EQ(tcs.head->y, initialY +2);
    //左移动
    tcs.status = LEFT;
    initialX = tcs.head->x;
    tcs.snakeMove();
    EXPECT_EQ(tcs.head->x, initialX -2);

    tcs.color(15);
    printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n测试蛇身移动结束,准备清空");
    Sleep(3000);
    system("cls");
}

TEST(SnakeGameTest, speedUp) {
    game tcs;
    int initialSpeed = tcs.speed;

    // 如果初始速度小于 280,调用加速函数
    if (initialSpeed < 280) {
        tcs.speedUp();
        // 期望速度加了 20
        EXPECT_EQ(initialSpeed + 20, tcs.speed);
    }
    else {
        // 如果初始速度已经是 280 或更高,加速函数不会改变速度
        EXPECT_EQ(initialSpeed, tcs.speed);
    }
}


TEST(SnakeGameTest, speedDown) {
    game tcs;
    int initialSpeed = tcs.speed;

    // 如果初始速度大于等于 120,调用减速函数
    if (initialSpeed >= 120) {
        tcs.speedDown();
        // 期望速度减了 20
        EXPECT_EQ(initialSpeed - 20, tcs.speed);
    }
    else {
        // 如果初始速度小于 120,减速函数不会改变速度
        EXPECT_EQ(initialSpeed, tcs.speed);
    }
    printf("\n\n\n\n\n\n\n\n测试移动速度结束,准备清空");
    Sleep(2000);
    system("cls");
}


TEST(SnakeGameTest, printFood) {
    game tcs;
    tcs.printGame();
    // 调用蛇身生成函数
    tcs.printSnake();

    // 调用食物生成函数
    tcs.printFood();

    // 获取食物的坐标
    int foodX = tcs.food->x;
    int foodY = tcs.food->y;

    // 食物坐标应在合法范围内
    EXPECT_GE(foodX, 2);
    EXPECT_LE(foodX, 48);
    EXPECT_GE(foodY, 1);
    EXPECT_LE(foodY, 24);

    // 检查食物是否与蛇身重叠
    snake* current = tcs.head;
    while (current) {
        EXPECT_FALSE(foodX == current->x && foodY == current->y);
        current = current->next;
    }
    tcs.gotoxy(0, 30);
    tcs.color(15);
    printf("测试食物生成是否合理结束,准备清空");
    Sleep(2000);
    system("cls");
}


TEST(SnakeGameTest, GameEndsOnWallCollision) {
    game tcs;

    // 设置蛇头,模拟碰到墙壁
    tcs.head= (snake*)malloc(sizeof(snake));
    tcs.head->x = 50;
    tcs.head->y = 10;
    tcs.color(15);
    // 调用游戏结束判定函数
    EXPECT_TRUE(tcs.encounterWall());
}

TEST(SnakeGameTest, SnakeBitesItself) {
    // 创建贪吃蛇实例
    game tcs;

    tcs.tail = (snake*)malloc(sizeof(snake));
    tcs.tail->x = 16;
    tcs.tail->y = 13;
    tcs.tail->next = NULL; 
 ;
    int a[7] = { 16,16,14,14,14,16,16 };
    int b[7] = { 13,12,12,13,14,14,13 };
    for (int i = 1; i <= 6; i++) {
        tcs.head = (snake*)malloc(sizeof(snake));
        tcs.head->next = tcs.tail;
        tcs.head->x = a[i];
        tcs.head->y = b[i];
        tcs.head->next = tcs.tail; // 新节点的next指向原来的蛇尾
        tcs.tail = tcs.head; // 更新蛇尾为新节点
    }
    // 输出蛇身
    int c = 1;
    snake* show=(snake*)malloc(sizeof(snake));
    while (tcs.tail->next)
    {
        tcs.gotoxy(tcs.tail->x, tcs.tail->y);
        tcs.color(c++);
        printf("★");
      
        tcs.tail = tcs.tail->next;
    }
    tcs.color(15);
    printf("\n\n\n\n\n\n\n\n");
  
    bool isBite = tcs.biteSelf();
        
    // 期望结果为 true,因为生成的蛇咬到了自己
    EXPECT_TRUE(isBite);
}



int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

运行点这
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值