4 ms·
Unit-testing a console app
- MaxBarraclough 6y agoPoor choice of title. It's about unit-testing a TUI application, as opposed to an 'ordinary' command-line application like curl or gcc.
- jmmv 6y agoAuthor here. Fair enough, but how common is the TUI term anyway? I've seen it in a few places, but it doesn't seem to be as generalized as GUI.
- MaxBarraclough 6y agoA valid concern. Perhaps Unit-testing an interactive command-line app? (I'd favour command-line over console to avoid any possible confusion with games consoles.)
- jmmv 6y agoHmm, maybe. That's why I added the "text editor" suffix to the title, to be specific about what I was referring to. "Interactive command-line app" could also be misinterpreted because any CLI that asks for user input on a line-oriented manner (e.g. a REPL) would qualify, right?
- MaxBarraclough 6y ago> I added the "text editor" suffix As it's pretty vital information I don't think it belongs in a subheading, which may be chopped when the post is submitted to a site like HN. > any CLI that asks for user input on a line-oriented manner (e.g. a REPL) would qualify, right? That's true, but it's more specific than console app. It would be a bit cumbersome to restate what TUI means in less obscure terms, although it wouldn't be the longest title known to man: Unit-testing a full-screen interactive command-line application.
- rualca 6y ago> That's why I added the "text editor" suffix to the title, to be specific about what I was referring to. That was not good not clear, as there are command line text editors like ed. https://en.wikipedia.org/wiki/Ed_(text_editor) https://en.wikipedia.org/wiki/Ed_(text_editor) Another way to disambiguate TUIs vs CLIs is to refer to the frameworks used to develop the app. For instance, mentioning ncurses or ncurses-based app is also frequently used to refer to TUIs.
- agumonkey 6y agoDon't worry it's not a big deal. Thanks for the article.
- rualca 6y ago> Fair enough, but how common is the TUI term anyway? It's pretty common when referring to text-based user interfaces, and when there's a clear distinction between a basic command line application. https://en.wikipedia.org/wiki/Text-based_user_interface https://en.wikipedia.org/wiki/Text-based_user_interface
- css 6y agoThese ideas are exactly what I have been looking for. A year or so ago I started working on a prototype tool[0] using `curses` and I never found a good way to test things beyond behavior of internal methods. In an effort to make it more portable I have started a re-write[1] in Rust (using `crossterm` this time). This mocking strategy seems like exactly what I need to fix this gap in the app's tests. [0] https://github.com/ReagentX/Logria-py https://github.com/ReagentX/Logria-py [1] https://github.com/ReagentX/Logria https://github.com/ReagentX/Logria
- jmmv 6y agoGlad to hear that you liked the post and that you'll try it in a project of yours! It'd be nice to hear about your experience later on. crossterm is a very nice library, and I suspect it'd be extended somehow to "natively" support the kind of mocking I presented in the post without having to add an intermediate abstraction layer.
- tstack 6y agoSlightly off topic... but, if you're interested in console logging tools, have you looked into https://lnav.org https://lnav.org or https://github.com/rcoh/angle-grinder/ https://github.com/rcoh/angle-grinder/ ?
- css 6y agoI looked into a lot of tools before I decided to build this and none of them fit into my workflow the way I wanted them to.
- hnrodey 6y agoI gave an internal talk the other week on "Writing Highly Testable Code". I created this GitHub repo to use as my source material. https://github.com/ryanrodemoyer/writing_testable_code https://github.com/ryanrodemoyer/writing_testable_code I created a cheesy pneumonic device to help remember the four principles. La.S.I.C. 1. Loosely couple your code from the entry point. * Entry points are consoles, apis, services, GUI's, etc. * The entry point always performs some type of setup or initialization. 2. Simultaneously write code and write test. * Will quickly discover what designer patterns are easy to easy, and which suck to test. 3. Isolate dependencies using classes and interfaces. * Use classes and interfaces to abstract/isolate/wrap away behavior with dependencies. 4. Constructors are for declaring dependency needs, not initialization!
- tstack 6y agoFor the Logfile Navigator (https://lnav.org https://lnav.org), I implemented a tool[0] to record console input/output and then replay the input while verifying the output. It basically works, but needs some usability improvement. For example, the expected output is the raw escape sequences, so it's hard to look at a diff and see what really happened. I think it can be improved, I just haven't found the time yet. [0] - https://github.com/tstack/lnav/blob/master/test/scripty.cc https://github.com/tstack/lnav/blob/master/test/scripty.cc
- calmoo 6y agoJust wanted to let you know that I use lnav every day extensively for my job and it makes my life 10x easier. Thanks for creating such a useful tool!
- BTBurke 6y agoI use something similar for snapshot testing in Go. It's been really useful for regression testing for anything that can be serialized to []byte. I've used it for CLI output and testing image processing. https://github.com/BTBurke/snapshot https://github.com/BTBurke/snapshot