Consider a module which exports a subroutine that connects to the Internet and returns a result:
unit module A;
sub download is export {
"result from internet" # Not the actual implementation, obviously.
}
And another module which imports and calls that subroutine:
use A; # imports &download into this lexical scope
unit module B;
sub do-something is export {
download().uc ~ "!!" # Does something which involves calling &download
}
Now I'd like to write unit tests for module B.
But I don't want the tests to actually connect to the Internet; I'd like them to use a mock version of subroutine download that is controlled by my test script:
use Test;
plan 2;
use B;
my $mock-result;
my &mock-download = -> { $mock-result }
# ...Here goes magic code that installs &mock-download
# as &download in B's lexical scope...
$mock-result = "fake result";
is do-something(), "FAKE RESULT!!", "do-something works - 1";
$mock-result = "foobar";
is do-something(), "FOOBAR!!", "do-something works - 2";
The problem is the missing magic code to override sub download...
In Perl 5, I think this could be achieved pretty easily using glob assignment, or even nicer with the help of Sub::Override or Test::MockModule.
But in Perl 6, the lexical scope of module B closes when it has finished compiling, and can thus no longer be modified by the time the test script is run (correct me if I'm wrong). So this approach doesn't seem possible.
How would one solve this task in Perl 6, then?
I.e. how would one write unit tests for B::do-something, without letting it call the real A::download?
The simplest approach might be to use wrap which is described in https://docs.perl6.org/language/functions#Routines but a prerequisite for that is the use soft; pragma which prevents inlining. You'd need to use soft; in module A:
unit module A;
use soft;
sub download is export {
"result from internet";
}
Module B:
unit module B;
use A;
sub do-something is export {
download.uc ~ "!!";
}
And the test script:
use Test;
use A;
use B;
&download.wrap({
"mock result";
});
is do-something, "MOCK RESULT!!", "mock a 'use'd sub";
# ok 1 - mock a 'use'd sub
Related
I've tried to make use of test fixtures in my project in kotlin. Unfortunately I have encountered a strange problem, probably a bug, in a component of the toolchain (not sure which one).
Normally a Kotlin function in main declared internal can be accessible from a unit test from the same package. There's a number of proofs supporting this claim, particularly Kotlin: Make an internal function visible for unit tests
Indeed if we have src/main/kotlin/ main.kt:
#file:JvmName("Main")
package org.example.broken_test_fixtures
internal fun sayHello(who: String): String = "Hello, $who!"
fun main() {
println(sayHello("world"))
}
and src/test/kotlin/SayHelloTest.kt:
package org.example.broken_test_fixtures
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class SayHelloTest {
#Test
fun testSayHello() {
val expected = "Hello, world!"
val actual = sayHello("world")
assertEquals(actual, expected)
}
}
the test is passed successfully with a regular build.gradle.kts:
plugins {
kotlin("jvm") version "1.3.61"
}
group = "org.example"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
testImplementation("org.junit.jupiter:junit-jupiter-api:5.5.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.5.2")
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
So far so good.
But with an addition of a single line into the plugins list:
id("java-test-fixtures")
the build of the test gets broken with the following error:
e: /home/work/users/alex/broken-test-fixtures/src/test/kotlin/SayHelloTest.kt: (10, 22): Cannot access 'sayHello': it is internal in 'org.example.broken_test_fixtures'
I've discovered that similar problems were mentioned in Gradle, Kotlin Gradle plugin bug trackers. Unfortunately I couldn't extract a solution from those issues. Perhaps, it's a different problem.
For the reader's convenience I have prepared a tiny repo on Github demonstrating the problem.
The built-in unit testing functionality (unittest {...} code blocks) seems to only be activated when running.
How can I activate unit tests in a library with no main function?
This is somewhat related to this SO question, although the accepted answer there deals with a workaround via the main function.
As an example, I would expect unit testing to fail on a file containing only this code:
int foo(int i) { return i + 1; }
unittest {
assert(foo(1) == 1); // should fail
}
You'll notice I don't have module declared at the top. I'm not sure if that matters for this specific question, but in reality I would have a module statement at the top.
How can I activate unit tests in a library with no main function?
You can use DMD's -main switch, or rdmd's --main switch, to add an empty main function to the set of compiled source files. This allows creating a unit test binary for your library.
If you use Dub, dub test will do something like the above automatically.
I have the following method to test, which uses a function imported from a package.
import x.y.z
func abc() {
...
v := z.SomeFunc()
...
}
Is it possible to mock SomeFunc() in Go?
Yes, with a simple refactoring. Create a zSomeFunc variable of function type, initialized with z.SomeFunc, and have your package call that instead of z.SomeFunc():
var zSomeFunc = z.SomeFunc
func abc() {
// ...
v := zSomeFunc()
// ...
}
In tests you may assign another function to zSomeFunc, one that is defined in tests, and does whatever the test wants it to.
For example:
func TestAbc(t *testing.T) {
// Save current function and restore at the end:
old := zSomeFunc
defer func() { zSomeFunc = old }()
zSomeFunc = func() int {
// This will be called, do whatever you want to,
// return whatever you want to
return 1
}
// Call the tested function
abc()
// Check expected behavior
}
See related / possible duplicate:
Testing os.Exit scenarios in Go with coverage information (coveralls.io/Goveralls)
One thing you can do is this:
import "x/y/z"
var someFunc = z.SomeFunc
func abc() {
...
v := someFunc()
...
}
And in your test file you would do this.
func Test_abc() {
someFunc = mockFunc
abc()
}
But make sure that you do this in a concurrent manner, if you have multiple TestXxx functions calling abc or setting someFunc you may be better of using a struct with a someFunc field.
Having function pointer and monkey patching it is the one of doing it. But then when you multiple functions to mock, you will have a number function pointers and unnecessarily you will have to call function using the function pointer only.
The better and the recommended idea to have an interface and make your function part of the struct implementing the interface. Once done that, you can generate mocks using some nice tools available for go.
I have been using this:
mockgen -source myModule.go -package myPackage -destination myModuleMock.go
You can install it by:
go get github.com/golang/mock
While creating a package level variable is a viable option, it comes with some restrictions. to name a few:
It discourages running parallel tests using t.Parallel() as there can be race conditions on different behaviors of mocked function.
it is dangerous as a future developer in the same package can accidentally update the implementation of this global variable.
another way is to pass along the methods you want to mock as arguments to the function to enable testability. In my case, I already had numerous clients calling this method and thus, I wanted to avoid violating the existing contracts. so, I ended up creating a wrapped function.
eg:
import (
z "x.y.z"
)
//this should replicate the type of function z from x.y.z
type operation func() resp
func wrappedAbc(op operation) {
....
resp := op()
....
}
func Abc() {
wrappedAbc(z)
}
now for testing the actual logic, you will test calls to wrappedAbc instead of abc and you would pass it a mocked operation. this will allow you to test all the business logic while not violating API contract with current clients of method Abc.
mockcompose uses an approach that allows you to generate a mocking class, you can direct mockcompose to include your selected dependency closure (any imported functions from other packages). In the mean time, it generates a cloned copy of your subject function with local overrides so that you can test against. You can embed code generation process with go generate, therefore ensure your cloned copy is always in-sync with your code changes.
Say you have a function functionThatUsesGlobalFunction that imports
Sprintf in package fmt.
func functionThatUsesGlobalFunction(
format string,
args ...interface{},
) string {
//
// skip fansy logic...
//
// call out to a global function in fmt package
return fmt.Sprintf(format, args...)
}
Your goal is to test functionThatUsesGlobalFunction with Sprintf in package fmt being mocked.
To do that, you can configure go generate with mockcompose as following:
mocks.go
//go:generate mockcompose -n mockFmt -p fmt -mock Sprintf
//go:generate mockcompose -n mockJson -p encoding/json -mock Marshal
//go:generate mockcompose -n clonedFuncs -real "functionThatUsesGlobalFunction,fmt=fmtMock"
package clonefn
go generate mockcompose will then generate plumbing classes for you, enable you to write test code as following:
package clonefn
import (
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
var fmtMock *mockFmt = &mockFmt{}
func TestClonedFuncs(t *testing.T) {
assert := require.New(t)
// setup function mocks
fmtMock.On("Sprintf", mock.Anything, mock.Anything).Return("mocked Sprintf")
// inside functionThatUsesMultileGlobalFunctions: fmt.Sprintf is mocked
assert.True(functionThatUsesGlobalFunction_clone("format", "value") == "mocked Sprintf")
}
Please checkout this for details.
I'm using inject-loader to mock dependencies for a Typescript project being unit tested. The service I'm testing has an import line like this:
import pnp, { SearchQuery, Sort, SortDirection, CamlQuery } from "sp-pnp-js";
For my test, I want to mock several of the functions on pnp, but keep the classes intact. In my unit test file, I've included this import:
import { SearchQuery, Sort, SortDirection, CamlQuery } from "sp-pnp-js";
Which gives my test access to the necessary classes. I've declared a mock service object:
// mock services
const mockPnp = {
default: { ... }
};
Which I'm wiring into my target class instance:
Service = require("inject!./sharepointservice")({
"sp-pnp-js": mockPnp
}).Service;
And everything works, so long as I don't run any code that references those classes (ie. SearchQuery). To get that to work, I tried adding it to the mock:
// mock services
const mockPnp = {
default: { ... },
SearchQuery: SearchQuery
};
However, I get a 'SearchQuery' only refers to a type, but is being used as a value here error.
I've tried casting to any (same error), tricks with modules and exports, with no luck. I'm supposed to be able to write any Javascript with Typescript, and this would work trivially in Javascript - what am I missing here?
According to the definition file SearchQuery is an interface, which means that you can not treat it as a value (as the error message says).
Typescript interfaces aren't being compiled into the js output, and you can not use them at runtime.
Technically, since its just for type safety, I can do this
t: MyInterface = {};
I often wrote my test code in the main function while developing an API but because D has integrated unittest I want to start using them.
My current work flow is the following, I have a script that watches for file changes in any .d files, if the scripts finds a modified file it will run dub build
The problem is that dub build doesn't seem to build the unittest
module foo
struct Bar{..}
unittest{
...
// some syntax error here
...
}
It only compiles the unittests if I explicitly run dub test. But I don't want to run and compile them at the same time.
The second problem is that I want to be able to run unittests for a single module for example
dub test module foo
Would this be possible?
You can program a custom test runner using the trait getUnittests.
getUnitTests
Takes one argument, a symbol of an aggregate (e.g. struct/class/module). The result is a tuple of all the unit test functions of that aggregate. The functions returned are like normal nested static functions, CTFE will work and UDA's will be accessible.
in your main() you should be able to write something that takes an arbitrary number of module:
void runModuleTests(Modules...)()
{
static if (Modules.length > 1)
runModuleTests!(Modules[1..$]);
else static if (Modules.length == 1)
foreach(test; __traits(getUnitTests, Modules[0])) test;
}
of course the switch -unittest must be passed to dmd