I have the following requirement for valid usernames:

  1. Only alphanumeric characters and -
  2. Must not start with a -

I wrote this regex (on Rubular):


Is there a better to test this requirement other than to iterate through all the possible scenarios? I'm doing something like this.

  # There much more, but for brevity's sake I'm only including a few
  illegal_chars = [ "~", "!", "@", "#", "$"]

  illegal_chars.each do |char|
    test "username does not accept #{char}" do
      user = users(:homer)
      user.username = "name#{char}"
      refute user.valid?, "Username should not be valid"

I'll repeat for cases where #{char} is at the beginning and end of the word.

  1. Am I testing too much? Is there a better way? Running 70 or 80 tests for something like this seems excessive.
  2. As an aside, can my regex be expressed better?

1 Answer 1


Your regex looks wrong, see my link below.

If your functional requirement is that usernames match a certain regex, then your tests should reflect that. It is wrong to test a bunch of edge cases that a generic regex catches.

See this. All you need in your test is to do:

username_regex = /^[a-z0-9][a-z0-9-]*$/i
passing_usernames = ['passing','pAsSing-PASS-'.....]
failing_usernames = ['-failing','failing#'....]
passing_usernames.each { |username| assert_match username_regex, username}
failing_usernames.each { |username| assert_no_match username_regex, username }

If you're getting your username from somewhere else then just plug that in the same way.

  • \$\begingroup\$ For Ruby, your regex will not work, but it's an easy fix: You need to add A-Z: ^[a-z0-9][a-zA-Z0-9-]+$ \$\endgroup\$
    – Mohamad
    Jan 14, 2015 at 11:11
  • 1
    \$\begingroup\$ @Mohamad I apologize, I forgot to copy part of the regex. You don't need A-Z in the regex, you can append i (for case insensitive) after the slash. Of course, both work, but this way is shorter. \$\endgroup\$ Jan 14, 2015 at 13:09
  • 1
    \$\begingroup\$ Assuming usernames can be of length one, you might want to change + to * in username_regex. \$\endgroup\$ Jan 15, 2015 at 5:53
  • 2
    \$\begingroup\$ You could also use a POSIX character class (which can only be used within brackets): username_regex = /^[:alnum:][[:alnum:]-]*$/. \$\endgroup\$ Jan 15, 2015 at 6:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.