2

How would I test this method within the code? Do I just need to put a value into the inputs I have or something else? It should test ISD is working by checking by properly creating a song with the correct details

static Song InputSongDetails()
{
    Console.WriteLine("What is the name of your song");
    string name = Console.ReadLine();

    Console.WriteLine("What is the artists name");
    string artist = Console.ReadLine();

    int records;
    Console.WriteLine("How many records did it sell");
    while (!int.TryParse(Console.ReadLine(), out records) || records < 0)
    {
        Console.WriteLine("That is not valid please enter a number");
    }
    return new Song(name, artist, records);
}
  • 3
    Possible duplicate of [C# unit test for a method which calls Console.ReadLine()](https://stackoverflow.com/questions/3161341/c-sharp-unit-test-for-a-method-which-calls-console-readline) – ProgrammingLlama Feb 05 '19 at 08:45
  • Do you want to write automated unit tests? If so, Console.ReadLine will need to be changed. – Robin Bennett Feb 05 '19 at 08:45
  • 1
    You could write an automated (unit) test, by replacing Console.In and Consiole.Out. But the better approach is to refactor into an input part and a validation/processing part. – H H Feb 05 '19 at 08:45
  • A mistake that is often made is to think about "how to mock/stub/..." something before to define "what to test". Please describe what your test should actually do? Do you want to test if something was written to the console? Or which property-values the returned song has? Or somthing different? There´s no such thing as "the test" for amethod, the same as there is no "the method". When you want to test a method you want that it behaves in an expected way under some conditions. However you neither providced those conditions nor how you expect your method to behave. – MakePeaceGreatAgain Feb 05 '19 at 08:52
  • @HimBromBeere It just needs to test that the method works correctly by creating a song with the correct details –  Feb 05 '19 at 08:54
  • And what is "correctly"? You seem to have some conditions that indicate what that means, e.g. when user typed "Hans" the songs author should be "Hans" also. – MakePeaceGreatAgain Feb 05 '19 at 08:55
  • @HimBromBeere The only condition is that records cannotbe astring or a negative value –  Feb 05 '19 at 08:58
  • Then I suppose you have three tests, not a single one. One for a string, one for a negative number and one "usual". – MakePeaceGreatAgain Feb 05 '19 at 09:01
  • @Umarfarooq99 do you know how to put breakpoint? i mean thats what we usually do before going the hard way, your method is simple. – M.kazem Akhgary Feb 05 '19 at 09:02
  • I agree M.kazem, don´t unit-test something which isn´t testable in itself for the sake of writing tests. Your member seems simple enough, just step through it and see what happens. – MakePeaceGreatAgain Feb 05 '19 at 09:03
  • @M.kazemAkhgary Yes i do know how to put in a breakpoint but for the moment I have to demonstrate unit-testing –  Feb 05 '19 at 09:24
  • @HimBromBeere Yes i do know how to put in a breakpoint but for the moment I have to demonstrate unit-testing –  Feb 05 '19 at 09:24

3 Answers3

6

The best approach would probably be to abstract away the Console using some interface. But, you can also pre-fill the In buffer of the Console with your desired data.

For example:

var data = String.Join(Environment.NewLine, new[]
{
    "Let it be",
    "Beatles",
    // ...
});

Console.SetIn(new System.IO.StringReader(data));

// usage:
var songName = Console.ReadLine();
var artistName = Console.ReadLine();

See MSDN

haim770
  • 48,394
  • 7
  • 105
  • 133
0

There are two ways you can test the input and or the method.

after each input print the result Console.WriteLine(MyVar)

static Song InputSongDetails()
{
    Console.WriteLine("What is the name of your song");
    string name = Console.ReadLine();
    Console.WriteLine(name)

    Console.WriteLine("What is the artists name");
    string artist = Console.ReadLine();
    Console.WriteLine(artist)

    int records;
    Console.WriteLine("How many records did it sell");
    while (!int.TryParse(Console.ReadLine(), out records) || records < 0)
    {
        Console.WriteLine("That is not valid please enter a number");
    }
    Console.WriteLine(records)
    return new Song(name, artist, records);
}

You can also separate the method to input param you already validated.

static Song InputSongDetails(string name,string artist, int records)
    {
        return new Song(name, artist, records);
    }

and then you can just create a simple unit test for the method

Please read https://learn.microsoft.com/en-us/visualstudio/test/unit-test-basics?view=vs-2017

Eitam Ring
  • 190
  • 1
  • 10
  • 1
    Although this doesn´t answer the "how to test the method" (which is pretty trivial after your refactoring though) it´s pretty good in "how to make my method (unit-)testable". – MakePeaceGreatAgain Feb 05 '19 at 08:56
  • This is how I understood his question , when asked "how would I test this method" he need to prepare his method to be "testable" – Eitam Ring 7 mins ago – Eitam Ring Feb 05 '19 at 09:08
  • @Umarfarooq99 There are a couple of ways to approach unit testing in any program , You should read the link I posted , You just create a set of inputs and assert the result at the end (since you know what you expect). Link for assert and unit test example: https://learn.microsoft.com/en-us/visualstudio/test/walkthrough-creating-and-running-unit-tests-for-managed-code?view=vs-2017 Mainly look at Assert.AreEqual(). – Eitam Ring Feb 05 '19 at 09:27
  • @Umarfarooq99 If something prevents you from changing the method you need to look at other ways to test this method , in the state you posted you cannot properly unit-test the method. – Eitam Ring Feb 05 '19 at 09:43
0

An example of a unit test for you. The code uses NSubstitute for mock object.

public class Song
{
    public string Name { get; }

    public string Artist { get; }

    public int Records { get; }

    public Song(string name, string artist, int records)
    {
        Name = name;
        Artist = artist;
        Records = records;
    }
}

public interface IInOutService
{
    void Ask(string question);

    string GetString();

    string AskValue(string question);
}

public class InOutService : IInOutService
{
    public void Ask(string question)
    {
        Console.WriteLine(question);
    }

    public string GetString()
    {
        return Console.ReadLine();
    }

    public string AskValue(string question)
    {
        Ask(question);
        return GetString();
    }
}

public class FactorySong
{
    private readonly IInOutService _inOutService;

    public FactorySong(IInOutService inOutService)
    {
        _inOutService = inOutService;
    }

    public Song Create()
    {
        var name = _inOutService.AskValue("What is the name of your song");
        var artist = _inOutService.AskValue("What is the artists name");

        int records;
        _inOutService.Ask("How many records did it sell");

        while (!int.TryParse(_inOutService.GetString(), out records) || records < 0)
        {
            _inOutService.Ask("That is not valid please enter a number");
        }

        return new Song(name, artist, records);
    }
}

[TestClass]
public class FactorySongTest
{
    [TestMethod]
    public void TestCreate()
    {
        var consoleService = Substitute.For<IInOutService>();
        var testString = "test";
        var testRecords = 1;

        consoleService.AskValue(Arg.Any<string>()).Returns(testString);
        consoleService.GetString().Returns(testRecords.ToString());

        var factory = new FactorySong(consoleService);
        var song = factory.Create();

        Assert.IsNotNull(song);
        Assert.IsTrue(testString == song.Name);
        Assert.IsTrue(testString == song.Name);
        Assert.AreEqual(testRecords, song.Records);
    }
}