1

Hi I am quite new on MVC and I am trying to create a simple conversion from Fahrenheit to Celsius along with its unit testing. Sorry in advance for putting all the code here.

This is my controller code:

public string Convert(double value,string option)
{
    string d;

    if(option=="1") {
        d = " To Celcius"+FahrenheitToCelsius(value).ToString();
    }
    else {
        d = " To Fahrenheit" + CelsiusToFahrenheit(value).ToString();
    }
    return "ConvertTo" + d;
}

public static double CelsiusToFahrenheit(double temperatureCelsius)
{
    double celsius = temperatureCelsius;
    return (celsius * 9 / 5) + 32;
}

public static double FahrenheitToCelsius (double temperatureFahrenheit)
{
    double fahrenheit = temperatureFahrenheit;
    return (fahrenheit - 32) * 5 / 9;
}

This is my View Page

protected void btnConvert(object sender, EventArgs e)
{
    if (DropDownList1.SelectedValue=="1"){
        double temp = TemperatureConverterController.FahrenheitToCelsius(double.Parse(TextBox1.Text));
        Literal1.Text = temp.ToString();
    }
    else{
        double temp = TemperatureConverterController.CelsiusToFahrenheit(double.Parse(TextBox1.Text));
        Literal1.Text = temp.ToString();
        Literal1.Text = temp.ToString();
    }
}

When i do this unit testing i got an error:

[TestMethod]
public void ConvertReturnsAViewResultWhenInputDataIsValid()
{
    //Arrange
    var controller = new TemperatureConverterController();

    //Act
    double x = 80;
    double y = 25;
    var result = controller.Convert(x, "1") as ViewResult;
    //    here i get this error under ViewResult //

    //Assert
    Assert.IsInstanceOfType(result, typeof(ViewResult));
}

[TestMethod]
public void ConvertAsksForAViewTemplateNamedConvert()
{
    //Arrange
    var controller = new TemperatureConverterController();
    String expectedViewTemplate = "Convert";

    //Act
    double x = 80;
    double y = 25;
    var result = controller.Convert(x, "1") as ViewResult;
    ////Assert
    Assert.AreEqual<String>(expectedViewTemplate, result.ViewName);
}

Error is:

Error   Cannot convert type 'string' to 'System.Web.Mvc.ViewResult' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion.

3 Answers 3

2

the problem is here

var result = controller.Convert(x, "1") as ViewResult;

your Convert method is returning string and you are casting it as ViewResult

Your convert method should looks like

public ActionResult Convert()
{
    //Make a Model class and pass it to View
    //...
    return View(model_class_object);
}

Alternatively you can make controller like this

public ActionResult Convert()
{
    ViewData["tempvalue"]=Convert(x, "1");
    //Make a Model class and pass it to View
    //...
    return View();
}

and on your View you can just print it

@ViewData["tempvalue"].ToString()
Sign up to request clarification or add additional context in comments.

Comments

0

Let's go backwards for a minute here.

Controller

public class ConvertController : Controller
{
    public ActionResult Convert(MyConvertViewModel vm)
    {
        if (vm == null) { return View("convert", new MyConvertViewModel { ShowResult = false }); }

        if (vm.Option == 1)
        {
            vm.Result = FahrenheitToCelsius(vm.Input);
            vm.OptionName = "Fahrenheit To Celsius";
        }
        else
        {
            vm.Result = CelsiusToFahrenheit(vm.Input);
            vm.OptionName = "Celsius to Fahrenheit";
        }
        vm.ShowResult = true;

        //not needed, just for an example
        ViewData.Add("glosrob-example", "A value goes here!");

        return View("convert", vm);
    }

    private static double CelsiusToFahrenheit(double temperatureCelsius)
    {
        double celsius = temperatureCelsius;
        return (celsius * 9 / 5) + 32;
    }

    private static double FahrenheitToCelsius(double temperatureFahrenheit)
    {
        double fahrenheit = temperatureFahrenheit;
        return (fahrenheit - 32)*5/9;
    }
}

public class MyConvertViewModel
{
    public double Result { get; set; }
    public int Option { get; set; }
    public double Input { get; set; }
    public string OptionName { get; set; }
    public bool ShowResult { get; set; }
}

View

@model MvcApplication1.Controllers.MyConvertViewModel
@{
    ViewBag.Title = "Convert";
}
<h2>Convert</h2>

@using (Html.BeginForm("convert", "convert", FormMethod.Post))
{
 <div>
     Let's convert some temperatures!
 </div>
 <div>
     @Html.LabelFor(x => x.Input, "Temp. To Convert")
     @Html.TextBoxFor(x => x.Input)
 </div>
 <div>
     @Html.LabelFor(x => x.Option, "Convert to ")
     @Html.DropDownListFor(x => x.Option, new List<SelectListItem>
     {
         new SelectListItem {Text = "Celsius", Value = "1"},
         new SelectListItem {Text = "Fahrenheit", Value = "2"}
     })
 </div>
 <div>
     <button type="submit">Convert It!</button>
 </div>
}
@if (Model.ShowResult)
{
    <p>@Model.OptionName : @Model.Input = @Model.Result</p>
}

disclaimer: there is a lot of shortcuts there, it is only included to give you an idea of what you should have.

So the view will post back data the user chooses, to the controller action Convert

The controller in turn will return a ViewResult object, and it will be rendered using the data captured in the view model MyConvertViewModel

Now we want to test this.

So here are some of the more important properties that it seems like you need to hook into

[TestMethod]
public void Not_A_Real_Test_But_Stuff_You_Will_Want_To_Use()
{
    //arrange
    var c = new ConvertController();

    //act
    var results = c.Convert(null) as ViewResult;

    //now results is a ViewResult or null

    var theViewModelProperty = results.Model as MyConvertViewModel;
    var exampleResult = theViewModelProperty.Result;
    var exampleInput = theViewModelProperty.Input;

    //etc

    //how about the view that was returned?
    var theViewName = results.ViewName;

    //or anything you put in the ViewData
    var theViewData = results.ViewData["glosrob-example"];

    Assert.Fail("This was not a real test!");
}

Hopefully this gives you an idea of how you can test for output from a controller method.

Edit: I'm not writing all your tests for you but as an e.g.

[TestMethod]
public void Convert_Should_Return_A_MyConvertViewModel()
{
    //arrange
    var c = new Controller();

    //act
    var result = c.Convert(null) as ViewResult;

    //assert
    Assert.IsNotNull(result);
    Assert.IsInstanceOfType(result.ViewModel, typeof(MyConvertViewModel));
}

[TestMethod]
public void Convert_Should_Return_The_Correct_View()
{
    //arrange
    var c = new Controller();

    //act
    var result = c.Convert(null) as ViewResult;

    //assert
    Assert.IsNotNull(result);
    Assert.AreEqual("convert", result.ViewName);
}

7 Comments

it works for view test and failed for this test: [TestMethod] public void ConvertAddsTemperaturePropertyToTheViewBag() { var controller = new TemperatureConverterController(); Double temperature = 77d; String convertTo = "fahrenheit"; String expectedViewDataKey = "Temperature"; var result = controller.Convert(temperature, "1") as ViewResult; Assert.IsTrue(result.ViewData.Keys.Contains(expectedViewDataKey)); }
Indeed, but you aren't adding anything to the ViewData collection, not in your original or my modified version. What should the controller action be doing? What does the user provide, and what should they expect as an outcome?
Controller action should be doing the conversion and user will provide conversion option from drop-list and a value and expect converted value. But i am bit confused about it as in the test method, assert check for ViewData.Keys which is looking for a string value. Isnt it should look for double converted value ?
OK gimme a few mins, I think I can see the problem here
Still i did not get the test pass. It giving me the Assert.Fail.Failed error. Actually i didnt get the idea of testing part at all.
|
0

In MVC the controller code should return an "ActionResult" object containing the model.

If the data you want to pass to view is simply a string use:

public ActionResult Convert()
{
    //...
    return View("your result here...");
}

You can refer to data returned by controller using the "Model" property in Views or Tests.

3 Comments

Thx for the suggestion, it does remove the error but still failing the test. this is the test result- Failed Assert.IsTrue failed.
I'm not at my machine to check, but should that be View("viewname", "your result here...") - otherwise it will interpret the result as the view name
Yes, you are right. The default view name is the name of the method so you can omit it.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.