Hacker News new | past | comments | ask | show | jobs | submit login
Unit-testing a console app (jmmv.dev)
44 points by jmmv on Dec 10, 2020 | hide | past | favorite | 18 comments



Poor choice of title. It's about unit-testing a TUI application, as opposed to an 'ordinary' command-line application like curl or gcc.


Author 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.


> 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


A 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.)


Hmm, 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?


> 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)

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.


> 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.


Don't worry it's not a big deal. Thanks for the article.


Kind of a big deal, as I only clicked on the article because I was interested.in checking some insight on how to test CLIs instead of TUIs.


You want a click refund ?


These 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

[1] https://github.com/ReagentX/Logria


Glad 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.


Slightly off topic... but, if you're interested in console logging tools, have you looked into https://lnav.org or https://github.com/rcoh/angle-grinder/ ?


I 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.


I 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


I 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

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!


For the Logfile Navigator (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


Just 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!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: