Tanya Branagan
Tanya Branagan

Reputation: 571

How to test methods involving strings in C#

I have an app which allows you to add student and lecturer details, and search them, and display them, etc. This is for a college assignment, and I have to test five of the methods I have created. Firstly, I'm not sure how to test a method involving strings, as all the testing methods I have seen involved a bank account app, and testing withdrawal and deposit methods seems easy as you just have to add and subtract numbers. I'm not sure at all how to test my, (for example) AddLecturer() method. I've tried to get one of the methods to throw an exception if a Status class that I created is entered correctly, but the program seems to still consider it an unhandled exception. How do I fix the exception so it's handled correctly, and how do I test these other methods?

Here's the main entry point to the app with all the methods.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DBSManagement
{
    public class College: Staff
    {
        public static List<Student> students = new List<Student>();
        public static List<Lecturer> lecturers = new List<Lecturer>();

        public static void Main()
        { 
            int choice;
            bool seeAgain = true;

                do
                {
                    Console.WriteLine("Press");
                    Console.WriteLine("1: To add a student");
                    Console.WriteLine("2: To add a lecturer");
                    Console.WriteLine("3: To search for a lecturer or student");
                    Console.WriteLine("4: To show the details of all enrolled students");
                    Console.WriteLine("5: To show the names of all lecturers");
                    Console.WriteLine("6: To show payroll details for a lecturer");
                    Console.WriteLine("7: To quit");
                    int.TryParse(Console.ReadLine(), out choice);

                    switch (choice)
                    {
                        case 1:
                            AddStudent();
                            break;
                        case 2:
                            AddLecturer();
                            break;
                        case 3:
                            SearchPerson();
                            break;
                        case 4:
                            ShowStudents();
                            break;
                        case 5:
                            ShowLecturers();
                            break;
                        case 6:
                            ShowPayrollDetails();
                            break;
                        case 7:
                            seeAgain = false;
                            break;
                        default:
                            Console.WriteLine("Invalid option selected");
                            break;
                    }
                } while (seeAgain);
            }
        public static void AddStudent()
        {
            Student student = new Student();
            Console.WriteLine("Enter student name:");
            if (Console.ReadLine() != null)
            {
                student.Name = Console.ReadLine();
            }
            else throw new ArgumentNullException("Please enter a name");

            Console.WriteLine("Enter student address:");
            student.Address = Console.ReadLine();
            Console.WriteLine("Enter student phone number:");
            student.Phone = Console.ReadLine();
            Console.WriteLine("Enter student email:");
            student.Email = Console.ReadLine();
            Console.WriteLine("Enter student PPSN:");
            student.PPSN = Console.ReadLine();
            Console.WriteLine("Enter student status (postgrad or undergrad):");
            EnterStat:
                string stat = Console.ReadLine().ToLower();
                if (stat == "postgrad" || stat == "undergrad")
                {
                    student.Status = (Status)Enum.Parse(typeof(Status), stat);
                }
                else
                {
                    Console.WriteLine("Please enter either postgrad or undergrad:");
                    goto EnterStat;
                }
            Console.WriteLine("Enter student ID:");
            int inStudentID;
            int.TryParse(Console.ReadLine(), out inStudentID);
            student.StudentID = inStudentID;
            students.Add(student);
        }

        public static void AddLecturer()
        {
            Lecturer lecturer = new Lecturer();
            Console.WriteLine("Enter lecturer name:");
            lecturer.Name = Console.ReadLine();
            Console.WriteLine("Enter lecturer address:");
            lecturer.Address = Console.ReadLine();
            Console.WriteLine("Enter lecturer phone number:");
            lecturer.Phone = Console.ReadLine();
            Console.WriteLine("Enter lecturer email:");
            lecturer.Email = Console.ReadLine();
            Console.WriteLine("Enter lecturer PPSN:");
            lecturer.PPSN = Console.ReadLine();
            Console.WriteLine("Enter lecturer ID:");
            lecturer.ID = Console.ReadLine();
            Console.WriteLine("Enter salary:");
            lecturer.Salary = decimal.Parse(Console.ReadLine());
            Console.WriteLine("Enter subject taught:");
            lecturer.SubjectTaught = Console.ReadLine().ToLower();
            lecturers.Add(lecturer);
        }

        public static void SearchPerson()
        {
            int searchChoice = 0;
            int studentSearch = 0;
            int lecturerSearch = 0;
            Console.WriteLine("Press:");
            Console.WriteLine("1 to search for a student");
            Console.WriteLine("2 to search for a lecturer");
            int.TryParse(Console.ReadLine(), out searchChoice);

            switch (searchChoice)
            {
                //search students
                case 1:
                    Console.WriteLine("Press:");
                    Console.WriteLine("1 to search by name");
                    Console.WriteLine("2 to search by student number");
                    int.TryParse(Console.ReadLine(), out studentSearch);

                    switch (studentSearch)
                    {
                        case 1:
                            Console.WriteLine("Enter student name:");
                            string studentNameSearch = Console.ReadLine();
                            bool sFound = false;
                            foreach (Student student in students)
                            {
                                if (student.Name.Contains(studentNameSearch))
                                {
                                    Console.WriteLine(student.ToString());
                                    sFound = true;
                                    break;
                                }
                            }
                            if (sFound == false)
                            {
                                Console.WriteLine("Student name not found");
                            }
                            break;

                        case 2:
                            int studentIDSearch;
                            bool IDFound = false;
                            Console.WriteLine("Enter student number:");
                            int.TryParse(Console.ReadLine(), out studentIDSearch);
                            foreach (Student student in students)
                            {
                                if (student.StudentID.Equals(studentIDSearch))
                                {
                                    Console.WriteLine(student.ToString());
                                    IDFound = true;
                                    break;
                                }
                            }
                            if (IDFound == false)
                            {
                                Console.WriteLine("Student name not found");
                            }
                            break;

                        default:
                            Console.WriteLine("Invalid option selected");
                            break;
                    }
                    break;
                //search lecturers
                case 2:
                    Console.WriteLine("Press:");
                    Console.WriteLine("1 to search by name");
                    Console.WriteLine("2 to search by course taught");
                    int.TryParse(Console.ReadLine(), out lecturerSearch);

                    switch (lecturerSearch)
                    {
                        case 1:
                            Console.WriteLine("Enter lecturer name:");
                            string lecturerNameSearch = Console.ReadLine();
                            bool lFound = false;
                            foreach (Lecturer lecturer in lecturers)
                            {
                                if (lecturer.Name.Contains(lecturerNameSearch))
                                {
                                    Console.WriteLine(lecturer.ToString());
                                    lFound = true;
                                    break;
                                }
                            }
                            if (lFound == false)
                            {
                                Console.WriteLine("Lecturer name not found");
                            }
                            break;

                        case 2:
                            Console.WriteLine("Enter course taught:");
                            string lecturerSubjectSearch = Console.ReadLine().ToLower();
                            bool subjectFound = false;
                            foreach (Lecturer lecturer in lecturers)
                            {
                                if (lecturer.SubjectTaught.Contains(lecturerSubjectSearch))
                                {
                                    Console.WriteLine(lecturer.ToString());
                                    subjectFound = true;
                                    break;
                                }
                            }
                            if (subjectFound == false)
                            {
                                Console.WriteLine("Subject not found");
                            }
                            break;

                        default:
                            Console.WriteLine("Invalid option selected");
                            break;
                    }
                    break;

                default:
                    Console.WriteLine("Invalid option selected");
                    break;
            }
        }

        public static void ShowStudents()
        {
            //sort list by name
            List<Student> SortedStudents = students.OrderBy(o => o.Name).ToList();

            foreach (Student student in SortedStudents)
            {
                Console.WriteLine(student);
            }
        }

        public static void ShowLecturers()
        {
            //sort list by name
            List<Lecturer> SortedLecturers = lecturers.OrderBy(o => o.Name).ToList();

            foreach (Lecturer lecturer in SortedLecturers)
            {
                Console.WriteLine(lecturer.Name);
            }
        }

        public static void ShowPayrollDetails()
        {
            Console.WriteLine("Enter lecturer name:");
            string lecturerNameSearch = Console.ReadLine();
            for (int i = 0; i < lecturers.Count; i++)
            {
                if (lecturers[i].Name == lecturerNameSearch)
                {
                    Console.WriteLine(lecturers[i].PayrollDetails());
                }
                else
                {
                    Console.WriteLine("Lecturer name not found");
                }
            }
        }
    }
}

Here are the test methods I have created so far.

using Microsoft.VisualStudio.TestTools.UnitTesting;
using DBSManagement;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DBSManagement.Tests
{
    [TestClass()]
    public class CollegeTests
    {
        [TestMethod()]
        [ExpectedException(typeof(ArgumentException))]
        public void AddStudentTest()
        {
            //arrange 
            string s = "student";
            Status status = (Status)Enum.Parse(typeof(Status), s);
            //act
            Student student1 = new Student("Name", "123 Fake St", "0851234567", "[email protected]", "7895459R", status, 12345678);
            //assert
            //handled by exception
        }

        [TestMethod()]
        public void AddLecturerTest()
        {
            Assert.Fail();
        }

        [TestMethod()]
        public void SearchPersonTest()
        {
            Assert.Fail();
        }

        [TestMethod()]
        public void ShowStudentsTest()
        {
            Assert.Fail();
        }

        [TestMethod()]
        public void ShowLecturersTest()
        {
            Assert.Fail();
        }

        [TestMethod()]
        public void ShowPayrollDetailsTest()
        {
            Assert.

This is the student class. I'm attempting to make it throw an exception if anyone enters a status other than postgrad or undergrad. These are enums.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DBSManagement
{
    public class Student : Person
    {
        private Status status;
        //auto-implemented properties
        public Status Status
        {
            get
            {
                return status;
            }
            set
            {
                if (value == Status.undergrad || value == Status.postgrad)
                {
                    status = value;
                }
                else throw new ArgumentException("Error: please select undergrad or postgrad");
            }
        }
        public int StudentID { get; set; }

        //empty constructor
        public Student() { }

        //constructor with parameters
        public Student(string name, string address, string phone, string email, string ppsn, Status status, int studentId)
            :base(name, address, phone, email, ppsn)
        {
            Status = status;
            StudentID = studentId;
        }

        //overridden ToString() method
        public override string ToString()
        {
            return string.Format("Name: {0}\nStudent Number: {1}\nAddress: {2}\nPhone: {3}\nEmail: {4}\nStatus: {5}",
                Name, StudentID, Address, Phone, Email, Status);
        }
    }
}

Upvotes: 0

Views: 341

Answers (2)

Andr&#233; C. Andersen
Andr&#233; C. Andersen

Reputation: 9375

If you want to do testing it would be easier if you separate your UI from the logic. You could for instance adopt a MVC pattern or something like that. Start by building all your data objects like Lecturer, Student, etc. These objects would be your data model. Then add the logic, or controls, which manipulate these data objects. There could be a AddLecturer(..) method in the control component. Finally make a UI, or view, which interacts with them without being fully intertwined like in your code. With regard to testing, you'll mainly be writing tests for methods in the control components and maybe the model. There are plenty of things to test. Take your add lecturer method:

  • Is the name longer than 3 characters?
  • Is there at least two names? (Maybe this is a too strong assumption?)
  • Is the phone number correctly formatted?
  • Is the e-mail correctly formatted?
  • Is the lecturer ID only numbers? (Although, I'd expect the lecturer ID is something generated by your system)
  • Is the PPSN well formatted?
  • Is the salary positive?
  • Is the salary under a ludicrously large amount?
  • Is the salary even a number?`
  • When adding a new lecturer to lecturers did it really get added? (Typically you'd never check this. We trust the basic collections, unless you wrote it yourself.)
  • etc.

Upvotes: 1

Anton Gogolev
Anton Gogolev

Reputation: 115799

You can test your code, but these tests will be very fragile (and, as @Scott Chamberlain noted, it won't be clear what they will be proving).

What you need to do is to "hide" that ugly Console.ReadLine() behind something you have "programmatic" control over. Func<string> would be ideal:

public static void AddStudent(Func<string> consoleReader)
{
    Student student = new Student();

    Console.WriteLine("Enter student name:");
    student.Name = Console.ReadLine();
    // ...        
}

With this, your tests become something like:

[Test]
void TestAddStudent()
{
    var n = 0;
    var strings = new[] {
        "Name", 
        "123 Fake St", 
        "0851234567", 
        "[email protected]", 
        "7895459R",
        // ...
    };

    Func<string> consoleReader = () => strings[n++];

    var student = AddStudent(consoleReader);

    Assert.AreEqual(strings[0], student.Name);
    // ...
}

Upvotes: 1

Related Questions