How Can Unit Tests On iOS with Xamarin and F# - ios

I am using Xamarin Studio 5.5 and I'd like to run my tests on the iOS simulator.
Sadly there is no template to create an iOS unit test project.

Create an empty F# project
Copy the following file (AppDelegate.fs) into your newly created project
namespace ioslibrarytests //obviously you can choose any namespace you want
open System
open MonoTouch.UIKit
open MonoTouch.Foundation
open MonoTouch.NUnit.UI
[<Register("AppDelegate")>]
type AppDelegate() =
inherit UIApplicationDelegate()
override val Window = null with get, set
override this.FinishedLaunching(app, options) =
this.Window <- new UIWindow(UIScreen.MainScreen.Bounds)
let runner = new TouchRunner(this.Window)
runner.Add (System.Reflection.Assembly.GetExecutingAssembly ());
this.Window.RootViewController <- new UINavigationController (runner.GetViewController ());
this.Window.MakeKeyAndVisible()
true
module Main =
[<EntryPoint>]
let main args =
UIApplication.Main(args, null, "AppDelegate")
0
Create your test file. for example Tests.fs and follow this implementation pattern
namespace ioslibrarytests
open System
open NUnit.Framework;
[<TestFixture>]
type Tests() =
[<Test>]
member me.Pass() = Assert.True (true)
[<Test>]
member me.Fail() = Assert.False (true)
[<Test>]
[<Ignore ("another time")>]
member me.``Ignore me``() = Assert.True (false)
Please take care that
your test class needs to have a default constructor => type Tests() = ...
your test methods need to have an empty param list => member me.Pass() = ...

Related

GraalJs - call constructor of java object

I want to use graal js to provide some scripting extension to my application
How can i initialize a new java object on the javascript side?
Context ctx = Context ctx = Context.newBuilder().allowHostAccess(HostAccess.ALL).allowAllAccess(true).build().create();
Value binding = ctx.getBindings("js");
binding.putMember("ArrayList", ArrayList.class);
ctx.eval("js","let list = new ArrayList();list.add(\"1\")");
List list = binding.getMember("list").as(List.class);
assert list.size() == 1;
following code throws exception
Exception in thread "main" TypeError: instantiate on JavaClass[java.util.ArrayList] failed due to: Message not supported.
at <js> :program(Unnamed:1:13-27)
at org.graalvm.polyglot.Context.eval(Context.java:371)
Running graalvm-ce-java11 19.3.2
You need to use Java.type.
Here is an example taken from https://www.graalvm.org/docs/reference-manual/polyglot/
var array = new (Java.type("int[]"))(4);
array[2] = 42;
console.log(array[2])
Here is a fully runnable example tested with GraalVM 20.0.0
import org.graalvm.polyglot.*;
class M {
public static void main(String[] args) {
try (Context context = Context.newBuilder().allowAllAccess(true).build()) {
java.util.ArrayList v = context.eval("js",
"var ArrayList = Java.type('java.util.ArrayList');" +
"var list = new ArrayList();" +
"list.add(1); list").asHostObject();
System.out.println(v.get(0));
assert v.get(0).equals(1);
}
}
}
Run with
graalvm-ce-java8-20.0.0/bin/javac M.java
graalvm-ce-java8-20.0.0/bin/java -ea M
To get 1 as output.
You could also use the sj4js library. There you can define constructors which seamlessly blend into JS.
// we create a new JS engine and add
// TestClass as a constructor. This constructor is added to globalThis such that it
// can be called as a costructor.
try (JScriptEngine engine = new JScriptEngine(new JsGlobalThis(),"gt")) {
engine.addConstructor(new TestClass("empty"));
/* call your js code here */
}
Your JS code than looks like this you would expect it.
// we create a new variable from the constructor
var tc = new TestClass("test");
console.log(tc.name)
// test

F# XUnit test deadlocks when initializer has dependency

I am having problems with a test in a netcoreapp2.2 .net core test project.
Before the tests starts I need to fetch some data that will be shared between the tests.
However, when running the following test from command line it will hang.
Executing the test like this:
dotnet test --filter "Test async initialization"
The faulty code looks like this:
let c = new HttpClient (BaseAddress = (Uri "https://swapi.co/api/people/1/"))
let luke =
async {
return! c.GetStringAsync "" |> Async.AwaitTask
} |> Async.RunSynchronously
[<Fact>]
let ``Test async initialization`` () =
Assert.NotNull(luke)
While if I put the creation of the HttpClient inside the luke fetcher like this it works:
let luke =
let c = new HttpClient (BaseAddress = (Uri "https://swapi.co/api/people/1/"))
async {
return! c.GetStringAsync "" |> Async.AwaitTask
} |> Async.RunSynchronously
[<Fact>]
let ``Test async initialization`` () =
Assert.NotNull(luke)
This means I can't share the same HttpClient between different fetchers.
Anyone knows what is going on, and how to share the same client between multiple functions?
The problem is caused because the "initialization" code isn't really initialization code. Those are just two static fields that will be evaluated only when requested. If you debug the unit test you'll see that c and luke execute only when execution reaches the line
Assert.NotNull(luke)
If you use a decompiler like JustDecompile you'll see that the module's code is placed in a static class called Tests$ whose static constructor initializes its own c and luke properties. Test async initialization is placed in a Tests class with its own c and luke properties that delegate to the Tests$ class.
Long story sort, none of that "initialization" code runs until the value of luke is requested. I don't know why that ends up blocking the test, most likely there's a conflict with the test runner. It's enough that the initialization code doesn't run at initialization.
To make the initialization code run when it should, a "classic" test type can be used :
namespace MyTests
open System
open Xunit
open System.Net.Http
open Xunit.Abstractions
type Tests() =
static let c = new HttpClient (BaseAddress = (Uri "https://swapi.co/api/people/1/"))
static let luke =
async {
return! c.GetStringAsync "" |> Async.AwaitTask
} |> Async.RunSynchronously
static do
//Pity we can't actually print here
printfn "Even more initialization!"
[<Fact>]
let ``Test async initialization`` () =
Assert.NotNull(luke)
The static bindings in this case are executed before any of the tests, as they should, and the code doesn't block. This initialization will happen only once.
To capture output the test class constructor should accept an ITestOutputHelper parameter. That's easy to do now that we have a test class :
type Tests(output:ITestOutputHelper) =
...
[<Fact>]
let ``Test async initialization`` () =
Assert.NotNull(luke)
output.WriteLine "It worked!"
Per-test initialization should go in a do block :
type Tests(output:ITestOutputHelper) =
do
output.WriteLine "This prints before each test"

Render component in Fable-Elmish

I have set up a standard SAFE application with the dotnet new SAFE command resulting in the two Server and Client projects (and the Shared folder).
The Client project has the Client.fs file with the view function and the bootstrapping code, which is just as the template generates it:
Program.mkProgram init update view
#if DEBUG
|> Program.withConsoleTrace
|> Program.withHMR
#endif
|> Program.withReact "elmish-app"
#if DEBUG
|> Program.withDebugger
#endif
|> Program.run
I have now added a simple component:
type MyComponentProps = {
data : int
}
type MyComponent(initialProps) =
inherit Component<MyComponentProps, obj>(initialProps)
do
base.setInitState({ data = initialProps.data })
override this.render() =
h1 [] [str ("Hello World " + this.props.data.ToString())]
override this.componentDidMount() =
// Do something useful here... ;)
console.log("Component Did Mount!")
But I cannot figure out how to properly instantiate this component in the view function. I really think this ought to work:
let view (model : Model) (dispatch : Msg -> unit) =
MyComponent({data = 42}) :> ReactElement
But this results in the browser in the - now - dreaded:
Error: Objects are not valid as a React child (found: object with keys {props, context, refs, updater, state}). If you meant to render a collection of children, use an array instead. I really don't get that since the type is ReactElement which should be fine...
Instantiating the component manually and calling render() does sort of work, but of course componentDidMount() is not called:
let myComponent = MyComponent({data = 42})
myComponent.render()
So: How do I get MyComponent properly instantiated and "injected" into React?
You can use ofType from Fable.Helpers.React
open Fable.Helpers.React
let view (model : Model) (dispatch : Msg -> unit) =
ofType<MyComponent,_,_> { data = 42 } []

Missing method exception while InvokeMember

I'm creating a COM component in F#. The component is expected to be used from scripting.
The component code:
namespace WebUIPlugin
open System
open System.Windows
open System.Runtime.InteropServices
[<Guid("BAEF0C5B-EFA5-4868-8342-7A1E6F8F7AF4")>]
type IPlugin =
[<DispId(1)>]
abstract OpenFormFromFile : path:string -> unit
[<Guid("8D71E2DB-D718-4595-B856-58D14EEAEBB2");
ClassInterface(ClassInterfaceType.None);
ComVisible(true)>]
type Plugin = class
new () = {}
interface IPlugin with
member this.OpenFormFromFile(path) =
let showWindow =
let window = Window()
window.Show
UI.spawn showWindow |> ignore
end
end
I'm registering it with regasm /codebase Plugin.dll and it works well from scripting cscript test.js.
test.js is following:
var obj = new ActiveXObject("WebUIPlugin.Plugin");
obj.OpenFormFromFile("");
It even stops on breakpoint in OpenFormFromFile. So good so far.
Unfortunately, I cannot make it work from F#/C#:
let objectType = Type.GetTypeFromProgID("WebUIPlugin.Plugin")
let handler = Activator.CreateInstance(objectType)
objectType.InvokeMember("OpenFormFromFile", BindingFlags.InvokeMethod, null, handler, [|""|]) |> ignore
var objectType = Type.GetTypeFromProgID("WebUIPlugin.Plugin");
dynamic handler = Activator.CreateInstance(objectType);
objectType.InvokeMember("OpenFormFromFile", BindingFlags.InvokeMethod, null, handler, new object[]{""});
The code throws exception:
An unhandled exception of type System.MissingMethodException occurred in mscorlib.dll
Additional information: Attempted to access a missing member.
Everything (component, test C# and F# projects, regasm, cscript) is either in x64 or x86 consistently. With the same result - WSH script works, .NET assembly does not.

Call interface method on F# object from C#

Given an F# type:
type Foo() =
member this.Prop with get() = ()
interface IDisposable with
member this.Dispose() = ()
In C#, I create the object, but I can't call Dispose():
var x = new Foo();
x.Dispose(); // compile error, x does not contain a definition of Dispose
However, I can write:
((IDisposable)x).Dispose(); // works, but I don't like the cast
Is there any way to avoid the cast in C#? Is this related to the way F# doesn't automatically let you call .Dispose() on the Foo type from within F#?
Interface implementations in F# are explicit by default. Hence the methods are not visible unless seen from the type converted to the interface (some form of casting).
To work around this expose an instance method which has the same signature as the interface version. Then have the interface on forward to the instance function. For example
type Foo() =
member this.Prop with get() = ()
member this.Dispose() = ()
interface IDisposable with
member this.Dispose() = this.Dispose()
How about, for this particular interface:
using (var x = new Foo()) {
...
}

Resources