2010-09-26 8 views
10

Tengo una función que lee la entrada de usuario de std :: cin, y quiero escribir una prueba de unidad que inserte algunas cadenas en std :: cin, de modo que la extracción posterior de std :: cin lee esa cadena en lugar de hacer una pausa para ingresar el teclado.Inyectando cadena a 'cin'

Idealmente, cambiaría la firma de la función para poder pasar una istream personalizada como parámetros, pero no puedo hacer eso porque tengo una interfaz fija que no puedo cambiar.

cin.putback() es casi lo que quería, sin embargo, es la inserción de un solo carácter a la vez, y les está insertando en orden inverso (pero he leído en alguna parte que volver a poner carbón que no era originalmente puede haber peligro, aunque el sitio web no explica por qué). He intentado varios métodos para inyectar la cadena al buffer interno de cin cin.rdbuf(), pero ninguno funcionaría tampoco. También consideré usar un script de prueba externo o crear un subproceso; sin embargo, me gustaría primero considerar una prueba en C++ puro.

Entonces, ¿hay algún método para poner cadenas en cin? ¿O conoces una forma mejor de inyectar mi "entrada de teclado falso"?

Respuesta

8

Si realmente, realmente desea utilizar std :: cin, intente esto:

int main() { 
    using namespace std; 
    streambuf *backup; 
    istringstream oss("testdata"); 
    backup = cin.rdbuf(); 
    cin.rdbuf(oss.rdbuf()); 
    string str; 
    cin >> str; 
    cout << "read " << str;  
} 

Puede restaurar streambuf de std :: cin cuando haya terminado la copia de seguridad. No garantizo la portabilidad de esto; P

+0

+1. o 'stringbuf sb (" testdata "); streambuf * backup = cin.rdbuf (&sb);). Es compatible, y razonablemente portátil, pero no es una buena práctica. Ah sí, y podría tener que hacer 'cin.clear()' para escapar de la condición EOF una vez que se ha agotado la entrada : vP. – Potatoswatter

+0

+1 exactamente lo que pedí (Todavía me estoy preguntando personalmente, si hacer algo como esto es una buena idea, incluso para un código de prueba de la caja blanca). –

13

En lugar de atornillar con cin, puede hacer que su programa acepte un std::istream& general. Cuando se ejecuta normalmente, simplemente páselo cin. Durante una prueba unitaria, páselo por un flujo de E/S de tu propia creación.

+2

Esta solución es realmente genial. Puede pasar un archivo abierto a través de 'ifstream' si desea pasar un archivo como su entrada de prueba, o simplemente puede pasar un' istringstream' si desea simplemente pasar una cadena como su entrada de prueba. – RPGillespie

0

cin.butback() se garantiza que funciona con un máximo de un carácter, por lo que no puede devolver una cadena completa. Utilice una secuencia que envuelve cin y permite una secuencia de bitback arbitraria(). Creo que Boost.Iostream tiene algo similar, y si no lo hace, podría ser útil implementar dicho wrapper.