I am new to Go and I am still trying to get my head around its concept. I am trying to create a simple unit test and want to Mock one of its service. I want to mock my_mod_2.EmpInfo in it so that I dont call the actual service.
method-1.go
package my_mod_1
import (
"awesomeProject-1/my-mod-2"
)
func CreateAndSendMail() string {
svc := my_mod_2.EmpInfo{}
name := svc.GetName()
empAddress := svc.GetAddress()
return name + " lives in " + empAddress
}
Here is Emp.go
package my_mod_2
import "fmt"
type EmpInfo struct {}
func (o EmpInfo) GetName() string{
fmt.Println("Called actual")
return "John Doe"
}
func (o EmpInfo) GetAddress() string {
return "US"
}
Here is the method-1_test.go
package my_mod_1
import (
"testing"
)
func TestCreateAndSendMail(t *testing.T) {
val := CreateAndSendMail()
if val != "John Doe lives in US" {
t.Error("Value not matched")
}
}
I am seeing Called actual in test execution. I Know I have to create a mock using interface but I am just not getting it. Can someone please help me out with this small code ?
First of all, you need to prepare your code to use interfaces and mocks. To do this I suggest you to declare Service interface beside CreateAndSendMail method. In this case, it is better to pass service instance to the method or use it as an instance variable of a struct to which your method is belong:
type Service interface {
GetName() string
GetAddress() string
}
func CreateAndSendMail(svc Service) string {
name := svc.GetName()
empAddress := svc.GetAddress()
return name + " lives in " + empAddress
}
or
type Service interface {
GetName() string
GetAddress() string
}
type S struct {
svc Service
}
func (s *S) CreateAndSendMail() string {
name := s.svc.GetName()
empAddress := s.svc.GetAddress()
return name + " lives in " + empAddress
}
Then, your EmpInfo will implement your Service interface implicitly. And this is a cool feature of golang interfaces.
After all our preparations, we are ready to create test. To do this, we can implement mocks by ourselves:
import (
"testing"
)
type MockSvc struct {
}
func (s *MockSvc) GetName() string {
return "Mocked name"
}
func (s *MockSvc) GetAddress() string {
return "Mocked address"
}
func TestCreateAndSendMail(t *testing.T) {
svc := &MockSvc{}
val := CreateAndSendMail(svc)
if val != "Mocked name lives in Mocked address" {
t.Error("Value not matched")
}
}
Also, we can use special tool gomock to automate mock creation process
Interfaces are the most used Go features that helps with testing. Interface in Go allows for Duck Typing where you can switch any type that has implemented an interface to be mocked by a different type.
From your example, the service has the following two methods: GetName() and GetAddress(). Create an interface Service with these two methods.
type Service Interface {
GetName() string
GetAddress() string
}
Now your struct EmpInfo, already implements the Service interface. Create a new MockService struct with same 2 functions.
type MockService struct {}
func (ms *MockService) GetName() string {
// Mock Code
}
func (ms *MockService) GetAddress() string {
// Mock Code
}
Then, replaces instances of EmpInfo with MockService wherever you need.
PS: Consider adding functions GetName and GetAddress with pointer to EmpInfo.
Related
Given:
// FileReader interface for reading from a file
type FileReader interface {
ReadFile(filename string) ([]byte, error)
}
type FileRead struct {}
// ReadFile reads from filename fn using ioutilReadFile
func (fr FileRead) ReadFile(fn string) ([]byte, error) {
return ioutil.ReadFile(fn)
}
type Dev struct {
*FileRead
}
func NewDev() *Dev {
frd := FileRead{}
return &Dev{frd}
}
// Function that does some job
func (dev Dev) DoSomeStuff() {
//...
dev.ReadFile("file")
//...
}
func main () {
doer := NewDev()
doer.DoSomeStuff()
}
During unit testing, the ReadFile operation should be mocked. How can one best achieve this in go test?
Dev struct could instead use FileReader interface, but then struct embedding is no longer used and the syntax in DoSomeStuff becomes less obvious.
If you are using a DI framework such as Dargo you can inject something that implements FileReader into dev. In your main-line code you would bind the normal FileReader, but in your test you can use a mock FileReader. The rest of your code should not know the difference. It would look something like this:
import (
"github.com/jwells131313/dargo/ioc"
"io/ioutil"
"testing"
)
type FileReader interface {
ReadFile(filename string) ([]byte, error)
}
type FileRead struct{}
// ReadFile reads from filename fn using ioutilReadFile
func (fr FileRead) ReadFile(fn string) ([]byte, error) {
return ioutil.ReadFile(fn)
}
type Dev struct {
MyReader FileReader `inject:"FileReader"`
}
/* Not here anymore, but you can implement DargoInitializer
if you need more initialization of Dev
func NewDev() *Dev {
frd := FileRead{}
return &Dev{frd}
}
*/
// Function that does some job
func (dev Dev) DoSomeStuff() {
//...
dev.MyReader.ReadFile("file")
//...
}
var locator ioc.ServiceLocator
func initialize() error {
l, err := ioc.CreateAndBind("Example", func(binder ioc.Binder) error {
binder.Bind("Dev", &Dev{})
binder.Bind("FileReader", &FileRead{})
return nil
})
locator = l
return err
}
func main() {
initialize()
raw, _ := locator.GetDService("Dev")
doer := raw.(*Dev)
doer.DoSomeStuff()
}
// Here is test code
type TestFileRead struct{}
// ReadFile is a mock that just returns a zero-length byte array
func (tfr TestFileRead) ReadFile(fn string) ([]byte, error) {
return []byte{}, nil
}
func TestMe(t *testing.T) {
initialize()
ioc.BindIntoLocator(locator, func(binder ioc.Binder) error {
binder.Bind("FileReader", &TestFileRead{}).Ranked(1)
return nil
})
// Test Me!
}
In the above example the "normal" file reader is injected in the normal code, but in the test there is a TestFileReader with a higher rank. So when you went to get Dev in the test it would be injected with the test one, not the one from the main-line code.
Hope this helps.
Hi I would like to test or Mock a certain function and return a Mock response for this. To demonstrate below is my code
Sample.go
package main
import (
"fmt"
log "github.com/sirupsen/logrus"
)
var connectDB = Connect
func Sample() {
config := NewConfig()
response := connectDB(config)
fmt.Println(response)
log.Info(response)
}
func Connect(config *Config) string {
return "Inside the connect"
}
And my test is like this
Sample_test.go
package main
import (
"testing"
)
func TestSample(t *testing.T) {
oldConnect := connectDB
connectDB := func(config *Config) string {
return "Mock response"
}
defer func() { connectDB = oldConnect }()
Sample()
}
So when running go test I was expecting to receive and output of Mock response but I'm still getting Inside the connect. Is there something I'm missing here?
#jrefior is correct, but I'd suggest to use interface for mocking. Of course, it's up to you, bet for me it is more clear, but more complicated code :)
// lack some fields :)
type Config struct {
}
// Use interface to call Connect method
type IConnection interface {
Connect(config *Config) string
}
// Real connection to DB
type Connection struct {
}
func (c Connection) Connect(config *Config) string {
return "Inside the connect"
}
// Mock connection
type MockConnection struct {
}
func (c MockConnection) Connect(config *Config) string {
return "Mock connection"
}
// Accepts interface to connect real or mock DB
func Sample(con IConnection) {
log.Println(con.Connect(nil))
}
func main() {
realConnection := Connection{}
Sample(realConnection)
mockConnection := MockConnection{}
Sample(mockConnection)
}
The use of a colon here creates a new function-scoped variable with the same name:
connectDB := func(config *Config) string {
return "Mock response"
}
Remove the colon to assign to the package variable.
I have next struct.
package logger
import "fmt"
type IPrinter interface {
Print(value string)
}
type ConsolePrinter struct{}
func (cp *ConsolePrinter) Print(value string) {
fmt.Printf("this is value: %s", value)
}
Test coverage says I need to test that ConsolePrinter Print method.
How can I cover this method?
Thanks.
Following comment that #icza wrote, I've written test below.
func TestPrint(t *testing.T) {
rescueStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
cp := &ConsolePrinter{}
cp.Print("test")
w.Close()
out, _ := ioutil.ReadAll(r)
os.Stdout = rescueStdout
if string(out) != "this is value: test" {
t.Errorf("Expected %s, got %s", "this is value: test", out)
}
}
I've found example in question What is the best way to convert byte array to string?.
Use Examples to convey the usage of a function.
Don't fret over 100% test coverage, especially for simple straightforward functions.
func ExampleHello() {
fmt.Println("hello")
// Output: hello
}
The additional benefit is that examples are outputted in a generated doc with go doc tool.
I would recommend to create new instance of the logger, which would behave exactly as fmt methods for printing data to console. Also, you can configure it with additional features like showing the filename, date and etc. Such custom logger can be passed as a parameter to your service/instance factory method. That would make it really easy to mock and test.
Your code
type Logs interface {
Println(v ...interface{})
}
type InstanceToTest struct {
log Logs
}
func InstanceToTestFactory(logger Logs) *InstanceToTest {
return &InstanceToTest{logger}
}
func (i *InstanceToTest) SomeMethod(a string) {
i.log.Println(a)
}
Create a mock for logger
type LoggerMock struct {
CalledPrintln []interface{}
}
func (l *LoggerMock) Println(v ...interface{}) {
l.CalledPrintln = append(CalledPrintln, v)
}
And in your test
func TestInstanceToTestSomeMethod(t *testing.T) {
l := &LoggerMock{}
i := InstanceToTestFactory(l)
a := "Test"
i.SomeMethod(a)
if len(l.CalledPrintln) == 0 || l.CalledPrintln[0] != a {
t.Error("Not called")
}
}
Given the following, how do I mock processMessage() using Spock, so that I can check that processBulkMessage() calls processMessage() n times, where n is the number of messages within a BulkMessage?
class BulkMessage {
List messages
}
class MyService {
def processBulkMessage(BulkMessage msg) {
msg.messages.each {subMsg->
processMessage(subMsg)
}
}
def processMessage(Message message) {
}
}
You can use spies and partial mocks (requires Spock 0.7 or newer).
After creating a spy, you can listen in on the conversation between the caller and the real object underlying the spy:
def subscriber = Spy(SubscriberImpl, constructorArgs: ["Fred"])
subscriber.receive(_) >> "ok"
Sometimes, it is desirable to both execute some code and delegate to the real method:
subscriber.receive(_) >> { String message -> callRealMethod(); message.size() > 3 ? "ok" : "fail" }
In my opinion this is not a well designed solution. Tests and design walk hand in hand - I recommend this talk to investigate it better. If there's a need to check if other method was invoked on an object being under test it seems it should be moved to other object with different responsibility.
Here's how I would do it. I know how visibility works in groovy so mind the comments.
#Grab('org.spockframework:spock-core:0.7-groovy-2.0')
#Grab('cglib:cglib-nodep:3.1')
import spock.lang.*
class MessageServiceSpec extends Specification {
def 'test'() {
given:
def service = new MessageService()
def sender = GroovyMock(MessageSender)
and:
service.sender = sender
when:
service.sendMessages(['1','2','3'])
then:
3 * sender.sendMessage(_)
}
}
class MessageSender { //package access - low level
def sendMessage(String message) {
//whatever
}
}
class MessageService {
MessageSender sender //package access - low level
def sendMessages(Iterable<String> messages) {
messages.each { m -> sender.sendMessage(m) }
}
}
It does not use Spock built-in Mocking API (not sure how to partially mock an object), but this should do the trick:
class FooSpec extends Specification {
void "Test message processing"() {
given: "A Bulk Message"
BulkMessage bulk = new BulkMessage(messages: ['a', 'b', 'c'])
when: "Service is called"
def processMessageCount = 0
MyService.metaClass.processMessage { message -> processMessageCount++ }
def service = new MyService()
service.processBulkMessage(bulk)
then: "Each message is processed separately"
processMessageCount == bulk.messages.size()
}
}
For Java Spring folks testing in Spock:
constructorArgs is the way to go, but use constructor injection. Spy() will not let you set autowired fields directly.
// **Java Spring**
class A {
private ARepository aRepository;
#Autowire
public A(aRepository aRepository){
this.aRepository = aRepository;
}
public String getOne(String id) {
tryStubMe(id) // STUBBED. WILL RETURN "XXX"
...
}
public String tryStubMe(String id) {
return aRepository.findOne(id)
}
public void tryStubVoid(String id) {
aRepository.findOne(id)
}
}
// **Groovy Spock**
class ATest extends Specification {
def 'lets stub that sucker' {
setup:
ARepository aRepository = Mock()
A a = Spy(A, constructorArgs: [aRepository])
when:
a.getOne()
then:
// Stub tryStubMe() on a spy
// Make it return "XXX"
// Verify it was called once
1 * a.tryStubMe("1") >> "XXX"
}
}
Spock - stubbing void method on Spy object
// **Groovy Spock**
class ATest extends Specification {
def 'lets stub that sucker' {
setup:
ARepository aRepository = Mock()
A a = Spy(A, constructorArgs: [aRepository]) {
1 * tryStubVoid(_) >> {}
}
when:
...
then:
...
}
}
i have just started using Moq ver (3.1) and i have read blogs and what not.... anyway... i guess until you makes your hand dirty you will not learn :)
okay here is what i'm testing...
var newProduct = new Mock<IPartialPerson>();
newProduct.SetupGet(p => p.FirstName).Returns("FirstName");
newProduct.SetupGet(p => p.MiddleName).Returns("MiddleName");
newProduct.SetupGet(p => p.LastName).Returns("LastName");
newProduct.SetupGet(p => p.EmailAddress).Returns("EmailAddress#hotmail.com");
newProduct.SetupGet(p => p.UserID).Returns("UserID");
//mock Escort repository
var mockEscortRepository = new Mock<IEscortRepository>();
mockEscortRepository.Setup(p => p.LoadAllEscorts())
.Returns(newProduct.Object); //error
Error 1 The best overloaded method
match for
'Moq.Language.IReturns>.Returns(System.Collections.Generic.List)'
has some invalid arguments
Error 2 Argument '1': cannot convert
from
'App.Model.Interface.IPartialPerson'
to
'System.Collections.Generic.List'
public interface IPartialPerson
{
string FirstName { get; }
string MiddleName { get; }
string LastName { get; }
string EmailAddress { get; }
string FullName { get; }
string UserID { get; }
}
public interface IEscortRepository
{
List<PartialPerson> LoadAllEscorts();
List<PartialPerson> SelectedEscorts(List<PartialPerson> selectedEscorts);
}
i have two methods that i want to test "LoadAllaEscorts" and "SelectedEscorts"
how would i do a test for both methods?
Try this:
mockEscortRepository
.Setup(p => p.LoadAllEscorts())
.Returns(new List<IPartialPerson>() { newProduct.Object } );
When you say:
.Returns(newProduct.Object)
You are asking Moq to return one specific object. The compiler sees that your method returns a list and so it will not compile unless you provide a list for it to return. So you need to create a list that contains the object you want to return then ask Moq to return that instead.
Based on your comments you might also be interested in testing a list with more than one item. To do that, create a list with more than one item, then ask the Mock to return that. Here is one way you could create a list with more than one item:
List<PartialPerson> escorts = new List<PartialPerson>();
for (int i = 0; i < 10; i++)
{
var escort = new Mock<IPartialPerson>();
escort.SetupGet(p => p.FirstName).Returns("FirstName" + i);
escort.SetupGet(p => p.MiddleName).Returns("MiddleName" + i);
escort.SetupGet(p => p.LastName).Returns("LastName" + i);
escort.SetupGet(p => p.EmailAddress).Returns(i + "EmailAddress#hotmail.com");
escort.SetupGet(p => p.UserID).Returns("UserID" + i);
escorts.Add(escort.Object);
}
mockEscortRepository
.Setup(p => p.LoadAllEscorts())
.Returns(escorts);
Good luck and keep on pimpin!
i have two methods that i want to test
"LoadAllaEscorts" and
"SelectedEscorts"
Those are methods on an interface. You don't write tests against an interface, or against mock objects. You write tests against concrete classes.
Somewhere you have an EscortRepository that implements IEscortRepository. I'm assuming that hits the database. Write integration tests against that.
Elsewhere in your code you probably have a class (call it "Foo") that has an IEscortRepository dependency injected into it (such as via a constructor parameter). When you want to write tests against the Foo class, you would use Moq to create a mock IEscortRepository returning fixed test data and pass that mock object into your Foo instance.
Another issue is that your IEscortRepository methods are returning (or taking as a parameter) List<PartialPerson>. Those should be IList<IPartialPerson> (or IEnumerable<T>, ICollection<T>, or ReadOnlyCollection<T>). The most important part is that the collection items should be an interface type (IPartialPerson).
+1 for magnifico, who had the code right:
using System;
using System.Collections.Generic;
using Moq;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var newProduct = new Mock<IPartialPerson>();
newProduct.SetupGet(p => p.FirstName).Returns("FirstName");
newProduct.SetupGet(p => p.MiddleName).Returns("MiddleName");
newProduct.SetupGet(p => p.LastName).Returns("LastName");
newProduct.SetupGet(p => p.EmailAddress).Returns("EmailAddress#hotmail.com");
newProduct.SetupGet(p => p.UserID).Returns("UserID");
var mockEscortRepository = new Mock<IEscortRepository>();
mockEscortRepository
.Setup(p => p.LoadAllEscorts())
.Returns(new List<IPartialPerson> {newProduct.Object});
IEscortRepository repository = mockEscortRepository.Object;
IList<IPartialPerson> escorts = repository.LoadAllEscorts();
foreach (IPartialPerson person in escorts)
{
Console.WriteLine(person.FirstName + " " + person.LastName);
}
Console.ReadLine();
// Outputs "FirstName LastName"
}
}
public interface IPartialPerson
{
string FirstName { get; }
string MiddleName { get; }
string LastName { get; }
string EmailAddress { get; }
string FullName { get; }
string UserID { get; }
}
public interface IEscortRepository
{
IList<IPartialPerson> LoadAllEscorts();
IList<IPartialPerson> SelectedEscorts(IList<IPartialPerson> selectedEscorts);
}
}
(The above example is not a unit test; it just shows that Moq works.)
Note that you don't have to use SetupGet for properties; Setup works as well.
Your mock is setup to return a single item, and it should return a List according to the repository interface.