如果您在Google或SO上搜索单元测试stdin stdout python'你会发现很多问题,每一个问题都以这种或那种方式回答
你真的需要对Python的内置
input
/sys.stdin
方法进行单元测试吗?
我的回答是是,我强调这样做,因为我实际上是在实施我自己的input
+穷人libreadline
/ {{ 1}},我需要使用stdin和终端的内容进行测试。
我碰巧使用Unix派生的操作系统,因此我有管道libcurses
和shell重定向|
,所以我可以编写一个小的shell脚本来执行此操作以及一些Python帮助程序代码,并进行测试终端的动作(ANSI转义序列,光标移动,确切打印的内容等)我可以从已知的<
读取,但有两个主要原因我不想这样做:
测试代码应该与它测试的代码一样跨平台(而不是那么脆弱!)
我非常喜欢/dev/tty/whatever
,谢谢你,我不想诉诸shell脚本和unix hackery(就像我喜欢unix hackery一样)只是为了测试我的模块。 / p>
必须有更好的方法来测试unittest
之类的内容,而不是在您使用 curses
进行时,但是当您开发时 a curses
。
既然有人提出要求,请参考以下我要测试的一些例子:(full code on github)
curses
答案 0 :(得分:2)
您可以使用subprocess
模块从python中调用脚本。然后,您可以通过communicate
import subprocess as sp
import sys
interpreter_path = sys.executable
p = sp.Popen([interpreter_path, script_to_test])
(stdout, stderr) = p.communicate(input = testinput)
然后可以测试 stdout
和stderr
的正确值
答案 1 :(得分:1)
这里的派对迟到了,但是:我正是在这种情况下,想要测试CLI的实际面向用户的部分,以便能够(i)确保由给定的一组用户按键导致的一致行为,(ii)检查打印到控制台的实际内容。
我把几个实现这个的类放在一起(在我看来是一个非常好的方式),最初实现here,并且在撰写本文时,现在发布在pyp上的v1.0预发行版中为stdio-mgr。其中大多数并不是特别新颖,只是一个模拟stdout
/ stderr
/ stdin
到临时流的上下文管理器,如this one,{等答案中所述。 {3}}和this one。
与我在别处看到的任何事情的最大区别在于stdin
被嘲笑为this one,其中(a)自动将从流中读取的所有内容转换为模拟的stdout
,从而将“打字输入”回应到“控制台”; (b)实现一个.append()
辅助方法,允许在模拟结尾添加更多内容 - stdin
,而不改变寻找位置。
使用示例:
>>> from stdio_mgr import stdio_mgr
>>> with stdio_mgr() as (in_, out_, err_):
... print('foobar') # 'print' appends '\n'
... in_.append('bazquux\n') # Don't forget trailing '\n'!
... inp_result = input('?') # 'bazquux\n' is teed to 'out_' here
... out_result = out_.getvalue() # Pull the whole 'out_' stream contents
>>> inp_result
'bazquux'
>>> out_result
'foobar\n?bazquux\n'
请注意,即使附加到in_
的字符串是换行符(否则执行会挂起),根据custom StringIO
subclass input
在字符串之前删除'\n'
存储在inp_result
中。可以看出,用作input
提示的问号也存储在out_
中。
但是,由于TeeStdin
在传递给stdin
之前从“input
”读取内容,out_
收到了?bazquux\n
?bazquux
},而不是#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
typedef struct param{
int id;
pthread_mutex_t lock;
sem_t *semaforo; //Dagan: change to a pointer to a semaphore
}valores_t;
void * olamundo(void* args){
valores_t* p = args;
sem_wait(*(&p->semaforo)); //Dagan: use the semaphore pointer
for (size_t i = 0; i < 25; i++) {
printf("Ola mundo da thread %d\n", p->id);
}
sem_post(*(&p->semaforo)); //Dagan: use the semaphore pointer
}
sem_t semaforo;
int main(int argc, char const *argv[]) {
/* code */
if(sem_init(&semaforo,0,1)){//valor inicial do semaforo começa por 1
printf("Erro ao iniciar o semaforo\n");
}
valores_t p[2];
pthread_t threads[2];
p[0].id = 1;
p[0].semaforo = &semaforo; //Dagan: pass the address of the semaphore
p[1].id = 2;
p[1].semaforo = &semaforo; //Dagan: pass the address of the semaphore
for(int i = 0; i < 2; i++){//inicia as funcoes das threads
if(pthread_create(&(threads[i]), NULL, &olamundo, &p[i]) == -1){
printf("Erro ao inicializar a thread\n");
}
}
for(int i = 0; i < 2; i++){
if(pthread_join(threads[i], NULL)){
printf("Erro ao sincronizar a thread\n");
}
}
sem_destroy (&semaforo);
return 0;
}
。虽然这种新行处理有可能会有些混乱,但我很确定没有太多可以做的事情 - 任何twiddles都可能从包装代码的角度打破模拟的透明度。