diff --git a/pkg/services/object/get/getrangeec_test.go b/pkg/services/object/get/getrangeec_test.go
new file mode 100644
index 000000000..b8497d7d1
--- /dev/null
+++ b/pkg/services/object/get/getrangeec_test.go
@@ -0,0 +1,182 @@
+package getsvc
+
+import (
+	"context"
+	"crypto/rand"
+	"fmt"
+	"testing"
+
+	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
+	coreContainer "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/container"
+	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
+	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/policy"
+	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object_manager/placement"
+	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger/test"
+	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
+	cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
+	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
+	objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
+	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/erasurecode"
+	oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
+	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/transformer"
+	"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
+	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
+	"github.com/stretchr/testify/require"
+)
+
+type containerStorage struct {
+	cnt *container.Container
+}
+
+func (cs *containerStorage) Get(cid.ID) (*coreContainer.Container, error) {
+	coreCnt := coreContainer.Container{
+		Value: *cs.cnt,
+	}
+	return &coreCnt, nil
+}
+
+func (cs *containerStorage) DeletionInfo(cid.ID) (*coreContainer.DelInfo, error) {
+	return nil, nil
+}
+
+func TestGetRangeEC(t *testing.T) {
+	var dataCount uint32 = 3
+	var parityCount uint32 = 1
+	cnr := container.Container{}
+	p := netmap.PlacementPolicy{}
+	p.SetContainerBackupFactor(1)
+	x := netmap.ReplicaDescriptor{}
+	x.SetECDataCount(dataCount)
+	x.SetECParityCount(parityCount)
+	p.AddReplicas(x)
+	cnr.SetPlacementPolicy(p)
+
+	var idCnr cid.ID
+	container.CalculateID(&idCnr, cnr)
+
+	ns, as := testNodeMatrix(t, []int{4})
+
+	testGetRange := func(t *testing.T, svc *Service, addr oid.Address, from, to uint64, payload []byte) {
+		w := NewSimpleObjectWriter()
+		rngPrm := newRngPrm(false, w, from, to-from)
+		rngPrm.WithAddress(addr)
+
+		err := svc.GetRange(context.Background(), rngPrm)
+		require.NoError(t, err)
+		if from == to {
+			require.Nil(t, w.Object().Payload())
+		} else {
+			require.Equal(t, payload[from:to], w.Object().Payload())
+		}
+	}
+
+	newSvc := func(b *testPlacementBuilder, c *testClientCache) *Service {
+		const curEpoch = 13
+
+		return &Service{
+			log:          test.NewLogger(t),
+			localStorage: newTestStorage(),
+			traverserGenerator: &testTraverserGenerator{
+				c: cnr,
+				b: map[uint64]placement.Builder{
+					curEpoch: b,
+				},
+			},
+			epochSource:              testEpochReceiver(curEpoch),
+			remoteStorageConstructor: c,
+			keyStore:                 &testKeyStorage{},
+			containerSource: &containerStorage{
+				cnt: &cnr,
+			},
+		}
+	}
+	const totalSize = 5
+	obj, parts := objectECChain(t, &idCnr, &cnr, totalSize, totalSize)
+	require.Len(t, parts, int(dataCount+parityCount))
+	require.Len(t, obj.Payload(), totalSize)
+
+	addr := object.AddressOf(obj)
+	builder := &testPlacementBuilder{
+		vectors: map[string][][]netmap.NodeInfo{
+			addr.EncodeToString(): ns,
+		},
+	}
+
+	clients := map[string]*testClient{}
+	for i, part := range parts {
+		builder.vectors[object.AddressOf(part).EncodeToString()] = ns
+
+		tc := newTestClient()
+
+		ecInfo := objectSDK.NewECInfo()
+
+		chunk := objectSDK.ECChunk{}
+		chunk.Total = uint32(len(parts))
+		chunk.Index = uint32(i)
+		id, _ := part.ID()
+		idv2 := refs.ObjectID{}
+		id.WriteToV2(&idv2)
+		chunk.ID = idv2
+
+		ecInfo.AddChunk(chunk)
+		errECInfo := objectSDK.NewECInfoError(ecInfo)
+
+		tc.addResult(addr, nil, errECInfo)
+		tc.addResult(object.AddressOf(part), part, nil)
+
+		clients[as[0][i]] = tc
+	}
+
+	svc := newSvc(builder, &testClientCache{
+		clients: clients,
+	})
+
+	for from := 0; from < totalSize-1; from++ {
+		for to := from; to < totalSize; to++ {
+			t.Run(fmt.Sprintf("from=%d,to=%d", from, to), func(t *testing.T) {
+				testGetRange(t, svc, addr, uint64(from), uint64(to), obj.Payload())
+			})
+		}
+	}
+}
+
+func objectECChain(t *testing.T, cnrId *cid.ID, cnr *container.Container, singleSize, totalSize uint64) (*objectSDK.Object, []*objectSDK.Object) {
+	pk, err := keys.NewPrivateKey()
+	require.NoError(t, err)
+
+	tt := new(testTarget)
+	p := transformer.NewPayloadSizeLimiter(transformer.Params{
+		Key:            &pk.PrivateKey,
+		NextTargetInit: func() transformer.ObjectWriter { return tt },
+		NetworkState:   testEpochReceiver(1),
+		MaxSize:        singleSize,
+	})
+
+	payload := make([]byte, totalSize)
+	_, err = rand.Read(payload)
+	require.NoError(t, err)
+
+	ver := version.Current()
+	hdr := objectSDK.New()
+	hdr.SetContainerID(*cnrId)
+	hdr.SetType(objectSDK.TypeRegular)
+	hdr.SetVersion(&ver)
+
+	ctx := context.Background()
+	require.NoError(t, p.WriteHeader(ctx, hdr))
+
+	_, err = p.Write(ctx, payload)
+	require.NoError(t, err)
+
+	_, err = p.Close(ctx)
+	require.NoError(t, err)
+
+	require.Len(t, tt.objects, 1)
+
+	c, err := erasurecode.NewConstructor(policy.ECDataCount(cnr.PlacementPolicy()), policy.ECParityCount(cnr.PlacementPolicy()))
+	require.NoError(t, err)
+	parts, err := c.Split(tt.objects[0], &pk.PrivateKey)
+	require.NoError(t, err)
+
+	return tt.objects[0], parts
+}