Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 7 years ago.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Improve this question
I am learning F# on my own and am trying to sneak some F# into the workplace.
As a result, I would like to write unit tests in F# to test C# logic.
Can anyone provide me a simple example of an F# unit test targeting a C# method and verifying a C# property as a result of exercising that method?
UPDATE:
Here's an example. When a value is provided for first and last name, how do we unit test (in F#) that GetFullName returns first and last name?
namespace MVVMExample
{
public class ViewModel : INotifyPropertyChanged
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
RaisePropertyChanged("FirstName");
}
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
RaisePropertyChanged("LastName");
}
}
public string GetFullName()
{
return string.Format("{0} {1}", FirstName, LastName);
}
protected void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
So a very simple test for this ViewModel using NUnit could look like this:
testing GetFullName
here is a possible test for this function:
[<Test>]
member __.``GetFullName = "Jon Doe" if FirstName = "Jon" and LastName = "Doh"``() =
let vm = ViewModel()
vm.FirstName <- "Jon"
vm.LastName <- "Doe"
Assert.AreEqual("Jon Doe", vm.GetFullName())
testing PropertyChanged
[<TestFixture>]
type ``ViewModel Unit Tests``() =
[<Test>]
member __.``a PropertyChanged event should be raised if the FirstName was changed``() =
let vm = ViewModel()
let mutable lastChangedProperty = ""
vm.PropertyChanged.Add (fun e -> lastChangedProperty <- e.PropertyName)
vm.FirstName <- "Tom"
Assert.AreEqual("FirstName", lastChangedProperty)
Of course this is not really functional but I think it should be reasonable clear for the given problem.
as you can see it's basically the same you would expect from a C# test - the only F# feature I used are the function/class names in ``...`` which makes the output in your test-runner look nicer:
Code Walkthrough
the [TestFixture] class Test {...} just translates into [<TestFixture>] type Test() = ...
a [Test] method is just [<Test>] member this.MyTestFunction() = ... (this only if you need it - as you can see I did not so I used the idiomatic I-don't-care __ placeholder - see in F# you can name your this-reference any way you want - and you have to do it on each class-member.
as I want to change the lastChangedProperty string if the event is fired I declared it mutable (so you can use the assign operator <-)
to add an event-handler you can just use the .Addfunction on the event
(fun e -> ..) is an lambda - in C# this would be e => ...
disclaimer
of course if you want to use this viewmodel in say a WPF application you should make sure to dispatch to the UI-Thread, etc. which would make the test more nasty but for your example a simple red-green cycle should work ;)
I hope this helps you out (but of course it does not really show the advantages of F# as the test here is ugly side-effecty)
Related
Basically we might have some data like so
open class RealmCart : RealmObject() {
#PrimaryKey
var _id: String = UUID.randomUUID().toString()
var items: RealmList<RealmCartItem> = RealmList()
var discountCode: String? = null
var userId: String = ""
}
And we do not want people editing these by mistake. We have some failsafe like code owners, labels in the repo, but we also want to have a unit test that can also prevent a merge if the data is changed in any way (add, change, or remove data). Basically, we do not want any accidents, and people are not perfect.
What is the best way to go about such a thing?
This is what I ended up doing:
I created an extension function for my data models
fun RealmObject.testDeclaredFields(): List<String> {
val fields = this::class.java.fields.map { it.name }
return this::class.java.declaredFields
.map { it.name }
.filterNot { fields.contains(it) }
.sorted()
}
Basically this just gets the data model fields, excluding things like companion objects.
Then I was able to create a test simply like
class RealmMessageTest {
#Test
fun `RealmMessage fields match spec`() {
val item = RealmMessage().testDeclaredFields()
assertContentEquals(item, fieldSpec)
}
private val fieldSpec = listOf(
"_id",
"acknowledgeStatusValue",
"body",
"completed",
"createdAt",
"deliveryStatusValue",
"from",
"meta",
"organizationId",
"platforms",
"threadId",
"title"
).sorted()
}
Why do this? Sometimes when someone is making changes carelessly, they will not realize that they have added a field, changed a field, or removed an important field in a data model that is sync'd to the backend. This does not prevent the developer from changing it, but given that they need to now change it in two places, they will be more cognizant whether they need to make this change or not.
I noticed a lot of people questioned why you would need to do this. My answer is that, I work in a very large repo where newer developers edit this without a second thought. This is just to make them more cognizant of changes to these important models, before they break develop. There are code owners for the repo, but they may not always see these changes. It is just an extra precaution.
How about using a mechanism like githooks to prevent the editing of certain files from being committed?
I'm not familiar with githooks, so I can't show you exactly how to do it, but I think it would be good to prevent commits and inform the developer of the situation with an error message.
I find it easy to write unit tests for algorithms. For example, sort(List), it is easy to write tests like:
list = [2, 1, 4];
assert(sort(list) == [1, 2, 4]);
But I find it really hard to test methods that have no logic, no if statements, just a set of calls.
There are mainly 2 examples that I'd like an answer for how to unit test them:
Example 1:
Let's say I have a class that is responsible for writing some data to a file, but that data is written in a specific way by external functions (writeHeaderToFile, writeSerializedData and writeEndOfFile).
The data is not written straight as it is to the file, so if data is something like:
{
list: [
"item 1",
"item 2"
],
name: "aaa"
}
That doesn't mean that the file will be neither the plain version of that data (without white spaces) nor it will be a simple serialized version or encrypted version into file. The actual file binary will be something unknown to me. All I know is that I can use those 3 methods to write in the right way.
This file also contains some other information that doesn't come directly from those 3 methods, like a specific type of header (that again, I have no idea how it will be represented in the file binary).
That is the class:
class FileCreator {
populateFileWithData(File file, Data data) {
doBlockWithLock(file, {
Header header;
header.format = SomeFormat;
header.version = SomeVersion;
writeHeaderToFile(file, header);
writeSerializedData(file, data);
writeEndOfFile(file);
});
}
// Private
void doBlockWithLock(File file, Lambda block) {
file.holdWritingLock();
block();
file.releaseWritingLock();
}
}
Example 2:
class Controller {
var screenOne = new ScreenOne();
var screenTwo = new ScreenTwo();
var screenThree = new ScreenThree();
void reloadButtonWasClicked() {
screenOne.reload();
screenTwo.reload();
screenThree.reload();
}
}
For this one I could do something like this:
var mockScreenOne = Mock<ScreenOne>().reload.expectOneCall();
var mockScreenTwo = Mock<ScreenTwo>().reload.expectOneCall();
var mockScreenThree = Mock<ScreenThree>().reload.expectOneCall();
Controller controller = new Controller();
controller.screenOne = mockScreenOne;
controller.screenTwo = mockScreenTwo;
controller.screenThree = mockScreenThree;
controller.reloadButtonWasClicked();
mockScreenOne.verify();
mockScreenTwo.verify();
mockScreenThree.verify();
But I don't find much value in it since I'm just asserting that I'm doing the same thing I'm doing in the implementation. Seems like code repetition to me.
What would be the proper way of testing my 2 examples?
In the first example, if you wrote the messages in question and satisfied with your test coverage, there's no reason to reproduce that testing logic on FileCreator. You just need to test the FileCreator populateFileWithData method to make sure the file is written and maybe that the locking mechanism works.
You are right, your last test is rather trivial. I'd be tempted to omit writing it. But it depends. Is it likely that someone might come along and comment out one of those panel constructors? Do you have other tests that would identify such a problem?
I am using F# and Foq to write unit tests for a C# project.
I am trying to set up a mock of an interface whose method has an out parameter, and I have no idea how to even start. It probably has to do with code quotations, but that's where my understanding ends.
The interface is this:
public interface IGetTypeNameString
{
bool For(Type type, out string typeName);
}
In C# Foq usage for the interface looks like this:
[Fact]
public void Foq_Out()
{
// Arrange
var name = "result";
var instance = new Mock<IGetTypeNameString>()
.Setup(x => x.For(It.IsAny<Type>(), out name))
.Returns(true)
.Create();
// Act
string resultName;
var result = instance.For(typeof(string), out resultName);
// Assert
Assert.True(result);
Assert.Equal("result", resultName);
}
As for how to achieve that with F#, I am completely lost. I tried something along the lines of
let name = "result"
let instance = Mock<IGetTypeNameString>().Setup(<# x.For(It.IsAny<Type>(), name) #>).Returns(true).Create();
which results in the quotation expression being underlined with an error message of
This expression was expected to have type IGetTypeNameString -> Quotations.Expr<'a> but here has type Quotations.Expr<'b>
Without any indication what types a and b are supposed to be, I have no clue how to correct this.
:?>
(It gets even wilder when I use open Foq.Linq; then the Error List window starts telling me about possible overloads with stuff like Action<'TAbstract> -> ActionBuilder<'TAbstract>, and I get even loster....)
Any assistance or explanation greatly appreciated!
Edit:
So, as stated here, byref/out parameters can not be used in code quotations. Can this be set up at all then in F#?
Foq supports setting up of C# out parameters from C# using the Foq.Linq namespace.
The IGetTypeNameString interface can be easily setup in F# via an object expression:
let mock =
{ new IGetTypeNameString with
member __.For(t,name) =
name <- "Name"
true
}
For declarations that have no analog in F#, like C#'s protected members and out parameters, you can also use the SetupByName overload, i.e.:
let mock =
Mock<IGetTypeNameString>()
.SetupByName("For").Returns(true)
.Create()
let success, _ = mock.For(typeof<int>)
I have seen multiple questions regarding as how to mock a companion object with frequently mentioned answer being to use scalamock but according to the doc for version 3, mocking companion objects is still marked for future.
So what is the way to mock a companion object? If not is there a better way to do things than what I already have to enable testing?
Code using play framework:
Model
case class Article(id: String, preview: String)
object Article {
def get(id: String) = {
......
}
}
ArticleResource
class ArticleResource extends Controller {
def getArticle(id: String) = authenticate {
......
Article.get(id)
......
}
}
How do I mock Article.get(id)?
Before when I had it working, I had structured the code differently:
Approach for working tests
Model
case class Article(id: String, preview: String)
Service
class ArticleService {
def get(id: String) = {
......
}
}
object ArticleService {
def apply = new ArticleService
}
ArticleResource
class ArticleResource(articleService: ArticleService) {
def getArticle(id: String) = authenticate {
......
articleService.get(id)
......
}
}
object ArticleResource extends controllers.ArticleResource(ArticleService())
In the test I injected a mock[ArticleService] into the Resource for testing.
I kept hearing the former approach (models) is the "right" approach, I never understood why so I tried it and ran into problems into testing and still I do not understand why it is the better approach. (I am actually feeling more strongly towards the latter approach now considering the difficulties with testing)
So I have 2 questions:
Is there a way to mock companion object?
Is there a "right" approach as how code is structured and if so why?
1) I don't think it's possible, and I don't think it's a good idea. I don't think it's desirable to put behavior-that-you-need-to-mock in companion objects.
2) I also believe that your first approach was better. If you want to keep your current code with minimal changes, how about that:
case class Article(id: String, preview: String)
object Article {
def get(id: String) = {
......
}
}
class ArticleResource(articleFinder: (String) => Article = Article.get) {
def getArticle(id: String) = authenticate {
......
articleFinder(id)
......
}
}
And when testing ArticleResource you can just create a function String => Article of your choice. You don't even need a framework for that :)
Edit: You can even use the companion object's method as default value to make it easier to instantiate in production code.
I'm trying out TDD on a greenfield hobby app in ASP.NET MVC, and have started to get test methods such as the following:
[Test]
public void Index_GetRequest_ShouldReturnPopulatedIndexViewModel()
{
var controller = new EmployeeController();
controller.EmployeeService = GetPrePopulatedEmployeeService();
var actionResult = (ViewResult)controller.Index();
var employeeIndexViewModel = (EmployeeIndexViewModel)actionResult.ViewData.Model;
EmployeeDetailsViewModel employeeViewModel = employeeIndexViewModel.Items[0];
Assert.AreEqual(1, employeeViewModel.ID);
Assert.AreEqual("Neil Barnwell", employeeViewModel.Name);
Assert.AreEqual("ABC123", employeeViewModel.PayrollNumber);
}
Now I'm aware that ideally tests will only have one Assert.xxx() call, but does that mean I should refactor the above to separate tests with names such as:
Index_GetRequest_ShouldReturnPopulatedIndexViewModelWithCorrectID
Index_GetRequest_ShouldReturnPopulatedIndexViewModelWithCorrectName
Index_GetRequest_ShouldReturnPopulatedIndexViewModelWithCorrectPayrollNumber
...where the majority of the test is duplicated code (which therefore is being tested more than once and violates the "keep tests fast" advice)? That seems to be taking it to the extreme to me, so if I'm right as I am, what is the real-world meaning of the "one assert per test" advice?
It seems just as extreme to me, which is why I a also write multiple asserts per test. I already have >500 tests, writing just one assert per test would blow this up to at least 2500 and my tests would take over 10 minutes to run.
Since a good rest runner (such as Resharper's) lets you see the line where the test failed very quickly, you should still be able to figure out why a test failed with little effort. If you don't mind the extra effort, you can also add an assert description ("asserting payroll number correct"), so that you can even see this without even looking at the source code. With that, there is very little reason left to just one assert per test.
In his book The Art of Unit Testing, Roy Osherove talks about this subject. He too is in favour of testing only one fact in a unit test, but he makes the point that that doesn't always mean only one assertion. In this case, you are testing that given a GetRequest, the Index method ShouldReturnPopulatedIndexViewModel. It seems to me that a populated view model should contain an ID, a Name, and a PayrollNumber so asserting on all of these things in this test is perfectly sensible.
However, if you really want to split out the assertions (say for example if you are testing various aspects which require similar setup but are not logically the same thing), then you could do it like this without too much effort:
[Test]
public void Index_GetRequest_ShouldReturnPopulatedIndexViewModel()
{
var employeeDetailsViewModel = SetupFor_Index_GetRequest();
Assert.AreEqual(1, employeeDetailsViewModel.ID);
}
[Test]
public void Index_GetRequest_ShouldReturnPopulatedIndexViewModel()
{
var employeeDetailsViewModel = SetupFor_Index_GetRequest();
Assert.AreEqual("Neil Barnwell", employeeDetailsViewModel.Name);
}
[Test]
public void Index_GetRequest_ShouldReturnPopulatedIndexViewModel()
{
var employeeDetailsViewModel = SetupFor_Index_GetRequest();
Assert.AreEqual("ABC123", employeeDetailsViewModel.PayrollNumber);
}
private EmployeeDetailsViewModel SetupFor_Index_GetRequest()
{
var controller = new EmployeeController();
controller.EmployeeService = GetPrePopulatedEmployeeService();
var actionResult = (ViewResult)controller.Index();
var employeeIndexViewModel = (EmployeeIndexViewModel)actionResult.ViewData.Model;
var employeeDetailsViewModel = employeeIndexViewModel.Items[0];
return employeeDetailsViewModel;
}
It could also be argued that since these tests require the same setup, they should get their own fixture and have a single [SetUp] method. There's a downside to that approach though. It can lead to lots more unit test classes than actual, real classes which might be undesirable.
I use a helper class to contain the asserts. This keeps the test methods tidy and focused on what they're actually trying to establish. It looks something like:
public static class MvcAssert
{
public static void IsViewResult(ActionResult actionResult)
{
Assert.IsInstanceOfType<ViewResult>(actionResult);
}
public static void IsViewResult<TModel>(ActionResult actionResult, TModel model)
{
Assert.IsInstanceOfType<ViewResult>(actionResult);
Assert.AreSame(model, ((ViewResult) actionResult).ViewData.Model);
}
public static void IsViewResult<TModel>(ActionResult actionResult, Func<TModel, bool> modelValidator)
where TModel : class
{
Assert.IsInstanceOfType<ViewResult>(actionResult);
Assert.IsTrue(modelValidator(((ViewResult) actionResult).ViewData.Model as TModel));
}
public static void IsRedirectToRouteResult(ActionResult actionResult, string action)
{
var redirectToRouteResult = actionResult as RedirectToRouteResult;
Assert.IsNotNull(redirectToRouteResult);
Assert.AreEqual(action, redirectToRouteResult.RouteValues["action"]);
}
}