How to add option to save app state in console application? - c#

I am using a constructor Employee(string id, string fullname, string roleid) in the business logic to add elements in the list Employees. The business logic I used is:
namespace ClassLibrary2
{
public class Employe
{
public List<Employee> Employees { get; set; } = new List<Employee>();
public void Add(Employee employee)
{
Employees.Add(employee);
}
public List<Employee> ViewAll()
{
return Employees;
}}}
The above business logic is executed in the below console application :
namespace EmployeeApp
{
static class Program
{
static void Main(string[] args)
{
Console.WriteLine("PPM Project");
Console.WriteLine("1. Add employee");
Console.WriteLine("2. View Employee");
Console.WriteLine("3. Save");
var userInput = Console.ReadLine();
var business1 = new Employe();
while (true)
{
switch (userInput)
{
case "1":
Console.WriteLine("adding employee full name:");
var FName = Console.ReadLine();
Console.WriteLine("adding 4digit Employee Id:");
var EmpId = Console.ReadLine();
var newEmployee = new Employee(EmpId, FName);
business1.Add(newEmployee);
Console.WriteLine($"An employee with EmployeeId {newEmployee.EmpId} was added. \n");
break;
case "2":
var allemployee = business1.ViewAll();
Console.WriteLine("\nList of Employees: \n");
foreach (var employee in allemployee)
{
Console.WriteLine($"Employee: {employee.EmpId}\t {employee.FName}.");
}
break;
case "3":
//how to save user input for further use
break;
}
Console.WriteLine("Select option");
userInput = Console.ReadLine();
}}}}
I want to save the app state so that when I restart the program I can retrieve the saved input. I tried saving the data in .txt file; using the How to permanently save input given by user in c# console application? but because I am providing user input in Lists in console rather than giving input in application, I am having trouble following the previous thread.

Related

How to search element in LinkedList with custom object

I need to find a node with input from a customer in the linked list but I have an error CS1503. How can I solve a problem?
In this code, I create the LinkList name "customerList" to collect string data such as name, contact number, and payment from the user. After that, I need to find the contact number which input from the user to show data in the node and delete it. In code show that input in "searchCustomerDetail" cannot convert 'string' to ....
Error Message: Argument 1: cannot convert from 'string' to 'IFN564.Customer' [IFN564]csharp(CS1503)
public class Customer {
public string Name { get; set; }
public string Phone { get; set; }
public string Payment { get; set; }
public int[] Screening { get; set; }
public static LinkedList<Customer> customerList = new LinkedList<Customer>();
public static string input;
public static void addCustomerDetail() {
Console.WriteLine("Please enter your information detail");
Console.WriteLine("");
Console.Write("Full Name: ");
string inputName = Console.ReadLine();
Console.Write("Contact Number: ");
string inputPhone = Console.ReadLine();
Console.Write("Payment Method: ");
string inputPayment = Console.ReadLine();
Console.Clear();
Console.WriteLine("");
Console.WriteLine("Please check your information detail!!");
Console.WriteLine("");
Console.WriteLine($"Full Name: {inputName}");
Console.WriteLine($"Contact Number: {inputPhone}");
Console.WriteLine($"Payment Method: {inputPayment}");
Console.WriteLine("");
Console.WriteLine("Please 1 to confirm or 0 to cancel");
int input = Convert.ToInt32(Console.ReadLine());
switch (input) {
case 1:
insert(inputName, inputPhone, inputPayment);
break;
case 2:
Program.Main();
break;
}
}
public static void insert(string name, string phone, string payment) {
Console.WriteLine("");
Console.WriteLine("Please 1 to confirm buy ticket or 0 to cancel");
int input = Convert.ToInt32(Console.ReadLine());
Customer customerDetail = new Customer() {
Name = name,
Phone = phone,
Payment = payment,
};
switch (input) {
case 0: Program.Main(); break;
case 1:
customerList.AddLast(customerDetail);
Program.Main();
break;
}
}
public static void searchCunstomerDetail() {
Console.WriteLine("Please enter contact number!!");
Console.WriteLine("");
Console.Write("Contact number: ");
input = Console.ReadLine();
LinkedListNode<Customer> node = customerList.Find(input);
Console.WriteLine(node);
}
}
I try to use LinkListNode to find but It show error with input CS1503
you need to use LINQ where
var node = customerList.Where(c=>c.Phone == input).First();
The error is with this statement:
LinkedListNode<Customer> node = customerList.Find(input);
customerList.Find searches the customerList for an element (in this case, a Customer) that equals the argument provided to Find (in this case, the var, input). input is a string, not Customer, so it can't be used in Find here.
What you seemingly intend to do here is to find the Customer in customerList that has a Customer.Phone that equals the input string. To do so, you can use LINQ, as others have suggested:
LinkedListNode<Customer> node = customerList.FirstOrDefault(c => c.Phone == input);
The above expression will find the first element in the list that returns true for the provided function (predicate), and will return null if none match.

How to create a group of unique users in C# console application with name, username and password where username is unique for all users?

I have a programming problem where I have to create a C# console application for login data. The data is username, password and the user's name. The username is unique for all users. I cannot use a text file or a database to store the data. The data can be stored in a data structure like an arraylist or dictionary or any other appropriate data structure. I tried to use a dictionary in a separate class where the key is supposed to be username and I have created a list comprising the corresponding password and the name, and inserted it in the dictionary. But I cannot achieve the required result as predicted as I don't know how to get the data to be stored exactly and retrieve it accordingly. Do I create a new object in a different class and store the data in there as a dictionary(or other data structure) or create a static method which contains a dictionary(or other data structure) and store the data there. I tried using an arraylist too but in vain.
->The data needs to persist as long as the application is running.
->The data needs to be available to make the user login after creating the username and password.
->The user must have a unique username authenticated by the key in data structure.
Any help is appreciated as I'm stuck with this for hours now. Just guide me where I am going wrong, whether in choosing the data structure or the whole logic altogether. Any suggestion is welcome.
I have created the program as follows:
using System;
using Users;
using System.Collections.Generic;
using System.Collections;
namespace Assignment_3
{
class Login
{
static void Main(string[] args)
{
int input;
do
{
Console.WriteLine();
Console.WriteLine("Choose one of the following:");
Console.WriteLine("1: Create a new Username and Password");
Console.WriteLine("2: Login");
Console.WriteLine("3: Exit");
Console.WriteLine();
input = Convert.ToInt32(Console.ReadLine());
switch (input)
{
case 1:
//Username and pass logic
Console.WriteLine("Enter a new Username");
string user = Console.ReadLine();
Console.WriteLine("Enter a new Password");
string pass = Console.ReadLine();
Console.WriteLine("Enter your full name");
string name = Console.ReadLine();
AllUsers.userList(user, pass, name);
ListOfAllUsers.Listy(user, pass, name);
/*RealUsers newUser = new RealUsers();
newUser.username = user;
newUser.password = pass;
newUser.name = name;
*/
break;
case 2:
//After successful login new code here
}
} while (input != 3);
}
}
}
namespace Users
{
class ListOfAllUsers
{
public ListOfAllUsers()
{
}
public static void Listy(string username,string password,string name)
{
ArrayList allInOne = new ArrayList();
List<string> threes = new List<string>();
threes.Add(password);
threes.Add(name);
allInOne.Add(username);
allInOne.Add(threes);
foreach (var item in allInOne)
Console.Write(item + ", ");
}
}
class RealUsers
{
public string name;
public string username;
public string password;
public Dictionary<String, List<String>> user()
{
Dictionary<string, List<String>> Usernames = new Dictionary<string, List<String>>();
List<string> passAndName = new List<string>();
passAndName.Add(password);
passAndName.Add(name);
Usernames.Add(username, passAndName);
return Usernames;
}
}
class AllUsers
{
public static void userList(string username, string password, string name)
{
Dictionary<string, List<String>> Usernames = new Dictionary<string, List<String>>();
List<string> passAndName = new List<string>();
passAndName.Add(password);
passAndName.Add(name);
Usernames.Add(username, passAndName);
foreach (KeyValuePair<string, List<string>> kvp in Usernames)
{
foreach (string value in kvp.Value)
{
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, value);
}
}
}
}
}
The logic to ensure unique entries in the Dictionary is much simpler than what you've posted. I'm not sure why you even have a separate namespace called Users with a bunch of classes that I don't see a need for. You can achieve what you want with just this code.
class Login
{
private static Dictionary<string, List<string>> AllUsers = new Dictionary<string,List<string>>();
static void Main(string[] args)
{
int input;
do
{
Console.WriteLine();
Console.WriteLine("Choose one of the following:");
Console.WriteLine("1: Create a new Username and Password");
Console.WriteLine("2: Login");
Console.WriteLine("3: Exit");
Console.WriteLine();
input = Convert.ToInt32(Console.ReadLine());
switch (input)
{
case 1:
//Username and pass logic
Console.WriteLine("Enter a new Username");
string user = Console.ReadLine();
while (AllUsers.ContainsKey(user))
{
Console.WriteLine("Username already exists. Enter a different Username");
user = Console.ReadLine();
}
Console.WriteLine("Enter a new Password");
string pass = Console.ReadLine();
Console.WriteLine("Enter your full name");
string name = Console.ReadLine();
AllUsers.Add(user, new List<string>() { pass, name });
break;
case 2:
//After successful login new code here
break;
}
} while (input != 3);
}
}
UPDATE: More refined answer, based on comments
Below is the same code, but it uses a class called "User" to be cleaner.
namespace Assignment_3
{
class Login
{
private static Dictionary<string, User> AllUsers = new Dictionary<string,User>();
static void Main(string[] args)
{
int input;
do
{
Console.WriteLine();
Console.WriteLine("Choose one of the following:");
Console.WriteLine("1: Create a new Username and Password");
Console.WriteLine("2: Login");
Console.WriteLine("3: Exit");
Console.WriteLine();
input = Convert.ToInt32(Console.ReadLine());
string user, pass, name;
switch (input)
{
case 1:
//Username and pass logic
Console.WriteLine("Enter a new Username");
user = Console.ReadLine();
while (AllUsers.ContainsKey(user))
{
Console.WriteLine("Username already exists. Enter a different Username");
user = Console.ReadLine();
}
Console.WriteLine("Enter a new Password");
pass = Console.ReadLine();
Console.WriteLine("Enter your full name");
name = Console.ReadLine();
AllUsers.Add(user, new User(user, pass, name));
break;
case 2:
Console.WriteLine("Enter your Username");
user = Console.ReadLine();
Console.WriteLine("Enter your Password");
pass = Console.ReadLine();
if (AllUsers.ContainsKey(user) && AllUsers[user].Password == pass)
{
Console.WriteLine($"Congratulations, {AllUsers[user].Name}, you are now logged in!");
}
else
{
Console.WriteLine("Login failed!");
}
break;
}
} while (input != 3);
}
}
}
namespace Users
{
class User
{
public string Username { get; private set; }
public string Password { get; private set; }
public string Name { get; private set; }
public User(string username, string password, string name)
{
Username = username;
Password = password;
Name = name;
}
}
}
With the caveat that there are glaring security concerns - but I get the impression this is more of an exercise than a project for publication - this could be done fairly simply by creating an object in which to store your data, and instantiating a list of that object in Main.
public class User{
string UserName {get; set;}
string Password {get; set;}
string Name {get; set;}
}
And then in Main:
List<User> UserList = new List<User>();
public void AddUser(){
User NewUser = new User();
//gather user data as you did in your example
UserList.Add(NewUser);
}
You can then iterate over that list as often as necessary when selecting a User object in your code.

C# create an association between nodes

I have a library class that has a Serve() method. What it does is dequeue a person from a queue and Pop a book from a stack. A Book is associated to a Borrower when it is borrowed, that way the method ReturnBook() can accept a string value that corresponds to the name of the person who borrowed the book.
How can I create an association between the Book and the Borrower? It's my first time encountering associations in C#. Here is a sample input and output
INPUT
Lineup("Joker")
Add("Shelter", "Yung Jun", "9781250075611")
Add("The Paper Menagerie and Other Stories", "Liu, Ken", "9781481442541")
Serve()
Joker lined up.
Added Shelter (Yung Jun) to the stack.
Added The Paper Menagerie and Other Stories (Liu, Ken) to the stack.
Joker borrowed Shelter (Yung Jun)
One way to do this is to create a property of one item that is of the type of the other item. For example, a Borrower may have a Book property. Then, when the borrower borrows a book, you just set the value of the Book property to the book they just borrowed.
Following is an illustrative example of how this might work:
To start with, you should create some classes to represent the objects. Here's an example:
class Reader
{
public string Name { get; set; }
public Book BorrowedBook { get; set; }
}
class Book
{
public string Title { get; set; }
public string Author { get; set; }
public string ISBN { get; set; }
}
And it looks like you have a Queue of Readers (called borrowers) and a Stack of Books. I also created a Queue of Readers called returners, which will represent the people who want to return a book:
class Program
{
private static Queue<Reader> borrowers = new Queue<Reader>();
private static Queue<Reader> returners = new Queue<Reader>();
private static Stack<Book> books = new Stack<Book>();
Now, it looks like you have some helper methods that will add a reader to the queue or a book to the stack. Since I can see that these may need to be used to add new items OR existing items (like when a reader returns a book, the existing book will get added back to the library), I create two versions of them - one with no arguments (which will then get the details of the object from the user), and one with an argument (which will add that object to the queue or stack):
private static void Lineup()
{
var newReader = new Reader();
Console.Write("Enter the name of the new reader: ");
newReader.Name = Console.ReadLine();
// Now that we have a reader object, call the
// other version of this method to add it
Lineup(newReader);
}
private static void Lineup(Reader borrower)
{
borrowers.Enqueue(borrower);
Console.WriteLine($"{borrower.Name} lined up to borrow a book.");
}
private static void Add()
{
var newBook = new Book();
Console.Write("Enter the book title: ");
newBook.Title = Console.ReadLine();
Console.Write("Enter the book author: ");
newBook.Author = Console.ReadLine();
Console.Write("Enter the book ISBN: ");
newBook.ISBN = Console.ReadLine();
// Now that we have a book object, call the
// other version of this method to add it
Add(newBook);
}
private static void Add(Book book)
{
books.Push(book);
Console.WriteLine($"Added '{book.Title}' to the library.");
}
Finally, we need some methods to service our borrowers (Dequeue a borrower and Pop a book, then give the book to the borrower) and our returners (Push the book back to the library, and, if the person wants to borrow another one, Enqueue them back in the borrowers line):
private static void ServiceBorrower()
{
if (borrowers.Count == 0)
{
Console.WriteLine($"There are no more borrowers waiting in line.");
}
else if (books.Count == 0)
{
Console.WriteLine($"There are no more books to loan.");
if (returners.Count > 0)
{
Console.WriteLine(" - Hint: There are people waiting to return books.");
}
}
else
{
var borrower = borrowers.Dequeue();
var book = books.Pop();
borrower.BorrowedBook = book;
Console.WriteLine($"{borrower.Name} borrowed {book.Title}");
returners.Enqueue(borrower);
}
}
private static void ServiceReturner()
{
if (returners.Count == 0)
{
Console.WriteLine($"There are no more returners waiting in line.");
}
else
{
var returner = returners.Dequeue();
var book = returner.BorrowedBook;
returner.BorrowedBook = null;
Add(book);
Console.WriteLine($"{returner.Name} has returned {book.Title}.");
Console.Write("Do they want to borrow another one (Y/N)?: ");
var input = Console.ReadKey();
Console.WriteLine();
if (input.Key == ConsoleKey.Y)
{
Lineup(returner);
}
}
}
Now, we just need to give our user some options as to what they want the program to do, and continue looping on their input until they decide to quit:
static void Main()
{
bool exit = false;
Console.WriteLine("Please choose an option:");
Console.WriteLine("1. Enter a new reader");
Console.WriteLine("2. Enter a new book");
Console.WriteLine("3. Service the next borrower");
Console.WriteLine("4. Service the next returner");
Console.WriteLine("5. Exit the program");
while (!exit)
{
Console.Write("\nEnter choice (1-5): ");
int input;
while (!int.TryParse(Console.ReadLine(), out input) || input < 1 || input > 5)
{
Console.Write("Invalid input. Enter a number from 1-5: ");
}
switch(input)
{
case 1:
Lineup();
break;
case 2:
Add();
break;
case 3:
ServiceBorrower();
break;
case 4:
ServiceReturner();
break;
case 5:
exit = true;
break;
}
}
Console.Write("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
Output:

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", "fake#address.com", "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);
}
}
}
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",
"fake#address.com",
"7895459R",
// ...
};
Func<string> consoleReader = () => strings[n++];
var student = AddStudent(consoleReader);
Assert.AreEqual(strings[0], student.Name);
// ...
}
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.

List containing class objects not working

I am working on a small C# program that will store student records in a list. I need to use a class to hold each student record, which is the top class in my code sample below.
If the user chooses to create a new record, I place their input into a studentRecord variable and then add it to the recordList. However, when I attempt to display the number of student records currently available using Count(), the program does nothing except re-display the menu, as if totally ignoring my command to display. I think something is wrong with how/where I declared the list, or with how I create a new StudentRecord object each time the menu is run.
Also, all three methods must stay in the first class. Is there any way to fix this?
public class StudentRecord
{
//Declare the various fields of the class
private string strFirstName;
private string strLastName;
private int intCourses;
private int intCreditHours;
List<StudentRecord> lstRecords = new List<StudentRecord>();
//Declare the properties of the class, since the fields are private
public string StrFirstName
{
get
{
return strFirstName;
}
set
{
strFirstName = value;
}
}
public string StrLastName
{
get
{
return strLastName;
}
set
{
strLastName = value;
}
}
public int IntCourses
{
get
{
return intCourses;
}
set
{
intCourses = value;
}
}
public int IntCreditHours
{
get
{
return intCreditHours;
}
set
{
intCreditHours = value;
}
}
//Declare a default constructor
public StudentRecord()
{
}
//Declare a constructor that takes the four necessary parameters, and set the class
// properties equal to the respective parameters
public StudentRecord(string firstName, string lastName, int courses, int creditHours)
{
strFirstName = firstName;
strLastName = lastName;
intCourses = courses;
intCreditHours = creditHours;
}
//Declare a method to perform the adding a student record function
public void mtdAddStudentRecord()
{
//These variables temporarily hold the various user inputs
string strInputFirstName;
string strInputLastName;
int intInputCourses;
int intInputCreditHours;
//Prompt the user to enter the student's first name
Console.Write("Please enter the first name: ");
strInputFirstName = Console.ReadLine();
//Prompt the user to enter the student's last name
Console.Write("Please enter the last name: ");
strInputLastName = Console.ReadLine();
//Prompt the user to enter the student's number of courses
Console.Write("Please enter the number of courses: ");
intInputCourses = int.Parse(Console.ReadLine());
//Prompt the user to enter the student's completed credit hours
Console.Write("Please enter the number of completed credit hours: ");
intInputCreditHours = int.Parse(Console.ReadLine());
//Add the new student record to the list, using the paramaters of the second
// class constructor
lstRecords.Add(new StudentRecord(strInputFirstName, strInputLastName,
intInputCourses, intInputCreditHours));
}
//Declare a method to perform the display student information option
public void mtdDisplayStudentInformation()
{
Console.WriteLine("Capacity: {0}", lstRecords.Count);
}
//Declare a method to perform the edit student information option
public void mtdEditStudentInformation()
{
//TODO
}
}
public class Program
{
public static void Main(string[] args)
{
//Declare and initialize a variable to store the user menu choice
string strMenuChoice;
strMenuChoice = "";
//Perform the necessary menu option while the user has NOT chosen to exit
do
{
//Call the reset method to clear the screen and display the header
mtdResetConsole();
//Display a menu to the user
Console.Write("Please choose an option to perform:" +
"\n - A) Display a list of existing students" +
"\n - B) Add a new student record" +
"\n - C) Edit an existing student record" +
"\n - D) Exit the program" + "\n\n" + " ");
//Store the user reply
strMenuChoice = Console.ReadLine().ToLower();
//Create a new StudentRecord object, and use it to call the various methods
// as chosen by the user
StudentRecord studentRecord = new StudentRecord();
//Determine which option was chosen, and take the appropriate action
switch (strMenuChoice)
{
case "a":
//TODO - Necessary code for option A
mtdResetConsole();
//Perform the "view student records" method
studentRecord.mtdDisplayStudentInformation();
break;
case "b":
//TODO - Necessary code for option B
mtdResetConsole();
//Perform the "add student record" method
studentRecord.mtdAddStudentRecord();
break;
case "c":
//TODO - Necessary code for option C
break;
case "d":
//Exit the program
Environment.Exit(0);
break;
default:
mtdResetConsole();
Console.WriteLine("Error" + "\n" +
" - Please choose a valid option from the list");
//Pause the code from executing for 2.5 seconds, so that the error
// message will be displayed
System.Threading.Thread.Sleep(2500);
break;
}
}
while (strMenuChoice.ToLower() != "d");
}
//Declare a method to reset the console with a blank screen and header
public static void mtdResetConsole()
{
Console.Clear();
Console.WriteLine("CONESTOGA STUDENT RECORDS" + "\n");
}
}
First, put this outside do while
StudentRecord studentRecord = new StudentRecord();
Putting this inside do while means that the object will reset in every loop.
2nd, try to put something like Console.ReadLine() on mtdDisplayStudentInformation method to hold the screen.
public void mtdDisplayStudentInformation()
{
Console.WriteLine("Capacity: {0}", lstRecords.Count);
Console.ReadLine();
}
Kendall, try to separate the logic of your "Records" and your "List of records".
In the case bellow, you have a "list of records" for each record you create.
Suggestions are you create a static variable to make sure it is always the same list on all "Records" or you separate as bellow:
public class StudentRecord
{
//Declare the various fields of the class
private string strFirstName;
private string strLastName;
private int intCourses;
private int intCreditHours;
...
}
public class Program
{
private List<StudentRecord> records = new List<StudentRecord>();
public static void Main(string[] args)
{
...
}
}

Categories