archseer/ruby-mpd

Discussion: how to best test complex interactions?

Closed this issue · 2 comments

I've put a question on Stack Exchange Code Review:
http://codereview.stackexchange.com/q/120345/3060

In short, I am writing tests for the command_lists functionality and expected results for ugly edge cases. I welcome any opinions on a better way to simulate MPD getting and sending information.

The two changes I plan to make beyond what I put there are:

  1. Instead of one monolithic recording of requests and responses, I'd prefer a more modular approach of smaller recordings that are easier to handle. Maybe one recording file per 'feature', or maybe even (!) one recording file per streak of commands sent. (Where the filename is the SHA-1 hash of the commands sent?)
  2. Instead of impenetrable Marshal files for the recordings, which can't be hand-edited, I want some sort of plain-text syntax. If I have one file per response, the contents of the file can BE the response, one on each line. I like that.

I've come up with a good solution, I think. It's in the 'answer' to the link above. The hash-for-filename was a bad idea, because it does not identify the files, and makes it very hard to edit them.

Instead, I've got test files like this sitting in a directory:

initialversion.recording

--putsabove--getsbelow--
OK MPD 0.19.0

listplaylists.recording

listplaylists
--putsabove--getsbelow--
playlist: Mix Rock Alternative Electric
Last-Modified: 2015-11-23T15:58:51Z
playlist: SNBRN
Last-Modified: 2016-01-26T00:25:52Z
playlist: Enya-esque
Last-Modified: 2015-11-18T16:19:12Z
playlist: RecentNice
Last-Modified: 2015-12-01T15:52:38Z
playlist: Dancetown
Last-Modified: 2015-11-18T16:19:26Z
playlist: Piano
Last-Modified: 2015-11-18T16:17:13Z
playlist: Thump
Last-Modified: 2015-11-20T15:32:30Z
playlist: GavinLikesIt
Last-Modified: 2015-11-20T15:54:49Z
OK

clear-and-add

command_list_begin
clear
addid test1.mp3
addid "test 2.mp3"
addid test3.mp3
command_list_end
--putsabove--getsbelow--
Id: 107
Id: 108
Id: 109
OK

...(more files)...

And now I can just do:

require '../lib/ruby-mpd'
require './socket_spoof'

class PlaybackMPD < MPD
  def initialize( recordings_directory=nil )
    super()
    @socket = SocketSpoof::Player.new(directory:recordings_directory)
  end
  def last_messages
    @socket.last_messages
  end
end

require 'minitest/autorun'
class TestQueue < MiniTest::Unit::TestCase
  def setup
    @mpd = PlaybackMPD.new 'socket_recordings'
  end

  def test_songs
    songs = @mpd.queue
    assert_equal ["playlistinfo"], @mpd.last_messages
    assert_equal 5, songs.length
    assert songs.all?{ |value| value.is_a? MPD::Song }
    assert_equal [310,226,243,258,347], songs.map(&:track_length)
  end

  def test_command_lists
    ids = @mpd.command_list(:values) do
      clear
      %w[test1.mp3 test\ 2.mp3 test3.mp3].each{ |f| addid(f) }
    end
    assert_equal(
      ["command_list_begin", "clear", "addid test1.mp3", 'addid "test 2.mp3"',
       "addid test3.mp3", "command_list_end"],
      @mpd.last_messages
    )
    assert_equal [107,108,109], ids

    pls = @mpd.command_list(:playlists){ playlists }
    assert_equal(
      ["command_list_begin", "listplaylists", "command_list_end"],
      @mpd.last_messages
    )
    assert_equal(8,pls.length)
    assert pls.all?{ |value| value.is_a? MPD::Playlist }
  end
end

Once I get a good suite of recordings saved (which, BTW, I can create super-easily by copy-pasting from a telnet-into-MPD session), I'll be checking this in as part of a test suite for command lists.